<!doctype html>



  


<html class="theme-next mist use-motion" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>



<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />












  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />




  
  
  
  

  
    
    
  

  

  

  

  

  
    
    
    <link href="//fonts.googleapis.com/css?family=Lato:300,300italic,400,400italic,700,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
  






<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.0" rel="stylesheet" type="text/css" />


  <meta name="keywords" content="chrisrc, christtrc, 前端, 后端, 系统架构, 微服务, Microservice, 容器, Docker, DC/OS, DCOS, Mesos, Marathon, Marathon-LB, HAProxy, VIPs, Rex-Ray, GlusterFS, Ceph, Prometheus, DevOps, Jenkins, IT自动化, 大数据, Storm, Spark, Akka, Cassandra, 互联网金融, 互联网彩票, 互联网, 移动互联网, 物联网, 博客, 个人网站, Hexo, NexT" />








  <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?v=5.1.0" />






<meta property="og:type" content="website">
<meta property="og:title" content="山中，山外与俯瞰">
<meta property="og:url" content="http://chrisrc.me/page/6/index.html">
<meta property="og:site_name" content="山中，山外与俯瞰">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="山中，山外与俯瞰">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Mist',
    sidebar: {"position":"left","display":"post"},
    fancybox: true,
    motion: true,
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://chrisrc.me/page/6/"/>





  <title> 山中，山外与俯瞰 </title>
</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  










  
  
    
  

  <div class="container one-collumn sidebar-position-left 
   page-home 
 ">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-meta ">
  

  <div class="custom-logo-site-title">
    <a href="/"  class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <span class="site-title">山中，山外与俯瞰</span>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>
  <p class="site-subtitle">一次永不停止的探索之旅</p>
</div>

<div class="site-nav-toggle">
  <button>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
  </button>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-dcos">
          <a href="/dcos" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-book"></i> <br />
            
            DC/OS
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-about">
          <a href="/about" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br />
            
            关于
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            标签
          </a>
        </li>
      

      
        <li class="menu-item menu-item-search">
          
            <a href="javascript:;" class="st-search-show-outputs">
          
            
              <i class="menu-item-icon fa fa-search fa-fw"></i> <br />
            
            搜索
          </a>
        </li>
      
    </ul>
  

  
    <div class="site-search">
      
  <form class="site-search-form">
  <input type="text" id="st-search-input" class="st-search-input st-default-search-input" />
</form>

<script type="text/javascript">
  (function(w,d,t,u,n,s,e){w['SwiftypeObject']=n;w[n]=w[n]||function(){
    (w[n].q=w[n].q||[]).push(arguments);};s=d.createElement(t);
    e=d.getElementsByTagName(t)[0];s.async=1;s.src=u;e.parentNode.insertBefore(s,e);
  })(window,document,'script','//s.swiftypecdn.com/install/v2/st.js','_st');

  _st('install', 'R9GcmhBwxpsAGLNCsquZ','2.0.0');
</script>



    </div>
  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            
  <section id="posts" class="posts-expand">
    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
  <link itemprop="mainEntityOfPage" href="http://chrisrc.me/2015/08/12/autoit-maven-nexus/">

  <span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <meta itemprop="name" content="chrisrc">
    <meta itemprop="description" content="">
    <meta itemprop="image" content="/images/avatar.gif">
  </span>

  <span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
    <meta itemprop="name" content="山中，山外与俯瞰">
    <span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject">
      <img style="display:none;" itemprop="url image" alt="山中，山外与俯瞰" src="">
    </span>
  </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2015/08/12/autoit-maven-nexus/" itemprop="url">
                  IT自动化(3)——持续开发的工程构建工具Maven/Nexus
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2015-08-12T12:46:18+08:00">
                2015-08-12
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
              <span class="post-meta-divider">|</span>
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/IT自动化/" itemprop="url" rel="index">
                    <span itemprop="name">IT自动化</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <a href="/2015/08/12/autoit-maven-nexus/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2015/08/12/autoit-maven-nexus/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          

          
          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="前文回顾"><a href="#前文回顾" class="headerlink" title="前文回顾"></a>前文回顾</h2><p><a href="/2015-08-11-autoit-support-tools">前文</a>我们简要讲述了现代软件开发过程中的各个环节以及可供选择用于支撑搭建自动化生产线<br>的各种工具。本文我们会对软件自动化构建工具Maven及Maven仓库软件SonaType Nexus做概要介绍，主要讲述这两者在IT自动化中<br>所起到的重要作用。</p>
<p>要想理解Maven，还要看Maven的由来（从<a href="http://maven.apache.org/" target="_blank" rel="external">官方网站</a>上可以看到详细了解）。</p>
<h2 id="Maven的由来"><a href="#Maven的由来" class="headerlink" title="Maven的由来"></a>Maven的由来</h2><p>在Maven之前，Ant是<br>用于Java构建的主要工具，当时的每个项目<br>都有自己的Ant构建描述，各个项目的构建描述差异很大，文件结构完全由开发人员自由定制，其他人员很难迅速理解项目结构及编译过程。<br>同时，项目生成的<br>构件如Jar文件都要传递到CVS，因为相同的代码，开发人员本地生成的Jar在CVS上不被看作同一个文件，导致协同困难。</p>
<p>正是基于上述原因，Maven的提出是想提供： <em>一个规范的项目结构描述用于所有开发人员快速理解项目模块划分</em>，<em>一个标准的编译过程来生成<br>项目编译构件</em>，<em>一个标准的构件发布和存储机制，用于构件在项目间的共享。</em></p>
<h2 id="Maven的实现"><a href="#Maven的实现" class="headerlink" title="Maven的实现"></a>Maven的实现</h2><h3 id="一个规范的项目结构描述"><a href="#一个规范的项目结构描述" class="headerlink" title="一个规范的项目结构描述"></a>一个规范的项目结构描述</h3><p>项目的结构根据技术、业务及构建项目的开发人员的不同，结构是复杂的。但总体来说，复杂的系统会拆分为可控的子系统，子系统又可以拆分<br>为具体的实现模块，这就形成了一棵类似目录树的项目结构树。这样就清晰了，我们在每个目录下放一个<code>pom.xml</code>，用于 <strong>标记</strong> 这些系统，<br>子系统和子模块。</p>
<p><img src="/images/autoit_3_maven_projects.png" alt="Maven Projects"></p>
<p>这些子系统、子模块，相互之间是可能存在依赖的。为了描述依赖关系，我们首先需要给这些子系统、子模块定义一个唯一标识，通常，一个<br>子系统或子模块在整个项目中会有一个分组关系，会有一个像目录名一样的系统/模块名，随着时间的推移，系统/模块会不断修改产生变化，<br>因此需要一个版本号，于是<code>pom.xml</code>里出现如下定义：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.example.greeter<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>greeter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">version</span>&gt;</span>1.0.0-SNAPSHOT<span class="tag">&lt;/<span class="name">version</span>&gt;</span></div></pre></td></tr></table></figure></p>
<p>系统、子系统和子模块，在存在的目的性上是不同的，系统、子系统的存在是为了聚合真正实现功能的子模块，因此是需要作出区分的：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">packaging</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">packaging</span>&gt;</span></div></pre></td></tr></table></figure></p>
<p>或<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">packaging</span>&gt;</span>jar<span class="tag">&lt;/<span class="name">packaging</span>&gt;</span></div></pre></td></tr></table></figure></p>
<p>有了项目结构描述，那么模块的具体实现如Java代码，资源文件，测试代码，测试用的资源等等，Maven如何识别呢？这一点，Maven采用了<br>约定俗称的结构，即：</p>
<ul>
<li>Java源代码： <code>src/main/java</code></li>
<li>Groovy源代码： <code>src/main/groovy</code></li>
<li>Scala源代码： <code>src/main/scala</code></li>
<li>资源文件： <code>src/main/resources</code></li>
<li>Java测试代码： <code>src/test/java</code></li>
<li>测试资源文件： <code>src/test/resources</code></li>
<li>Web资源文件： <code>src/main/webapp</code></li>
</ul>
<p>当然，在实际开发中你可以具体配置，采用不同的目录，如果不覆盖这些配置，工程编译时，Maven默认就从上述目录下查找项目资源。</p>
<p>前面提到，模块间是可能存在依赖的，这个问题怎么解决呢？ 首先，我们知道<br>（子）系统/模块的唯一标识有了，解决方案就是在POM中用<code>&lt;dependency&gt;</code>声明一下这个标识被依赖就可以了：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.example.greeter<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>greeter-api<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;project.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>biz.aQute.bnd<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>bndlib<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.1.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.felix<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>org.apache.felix.gogo.runtime<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.14.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></div></pre></td></tr></table></figure></p>
<p>到此，描述一个系统或者模块的POM定义已经基本完善了。 团队中的开发者，其他团队的开发者在阅读这个项目的所有POM后，对这个工程的结构功能就有了快速的认知。</p>
<h3 id="一个标准的编译过程"><a href="#一个标准的编译过程" class="headerlink" title="一个标准的编译过程"></a>一个标准的编译过程</h3><p>通过Maven POM我们对项目工程结构有了标准化的描述和认知，这就为一个标准化的编译过程打下了基础。编译过程的最终目的是为了获得用于<br>部署或共享的工程构件。以此为目标，结合Java最终构件jar/war/zip等的特点，我们可以总结编译过程包括：  </p>
<blockquote>
<p>准备资源文件 — 编译Java代码 — 准备测试资源 — 编译测试代码 — 执行测试 — 打包编译的代码和资源 — 发布构件以便共享</p>
</blockquote>
<p>这就是Maven的标准生命周期，如下图所示：</p>
<p><img src="/images/autoit_3_maven_lifecycle.png" alt="Maven Projects"></p>
<p>为了方便开发人员定制生命周期，在上述标准生命周期的两两环节之间还有其它环节，详细内容可参考Maven官方文档。</p>
<p>为了实现对生命周期的每一个阶段进行控制，Maven通过插件的概念来实现。由标准插件实现某一阶段的标准功能，由用户根据自己项目生命周期的<br>特点，定制自己的插件，配置进来，共同完成对生命周期的某个阶段的控制。标准生命周期对应的插件如下图所示：</p>
<p><img src="/images/autoit_3_maven_lifecycle_plugins.png" alt="Maven Projects"></p>
<p>关于Maven生命周期插件的支持，请参考<a href="http://maven.apache.org/plugins/index.html" target="_blank" rel="external">Maven插件中心</a></p>
<p>POM中的插件配置示例：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">build</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>biz.aQute.bnd<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>bnd-maven-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.4.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">executions</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">execution</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;<span class="name">goals</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">goal</span>&gt;</span>bnd-process<span class="tag">&lt;/<span class="name">goal</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;/<span class="name">goals</span>&gt;</span></div><div class="line">                <span class="tag">&lt;/<span class="name">execution</span>&gt;</span></div><div class="line">            <span class="tag">&lt;/<span class="name">executions</span>&gt;</span></div><div class="line">        <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">build</span>&gt;</span></div></pre></td></tr></table></figure></p>
<p>通过插件定义的工程项目生命周期有了，我们就可以执行这些插件提供的目标（Goals），对工程进行编译，测试，打包，发布。关于Maven命令请参考官方文档或通过搜索引擎获取相关介绍。</p>
<h3 id="一个标准的构件发布和存储机制"><a href="#一个标准的构件发布和存储机制" class="headerlink" title="一个标准的构件发布和存储机制"></a>一个标准的构件发布和存储机制</h3><p>编译打包工程的生命周期控制有了，发布的工程构件如何存放才能更好的实现共享和协作？为了解决这个问题，Maven提出了 <strong>仓库（Repository）</strong> 的概念。仓库是一个集中存放项目编译构件的地方，Maven在处理Maven项目时，根据POM中定义的依赖<code>&lt;dependency&gt;</code>会到中央仓库去自动下载这些依赖，如此，开发人员<br>就再也不用关心工程依赖的其它模块，依赖的第三方构件如何存放和维护，大量的依赖造成源代码工程的空间耗用的尴尬也就不存在了。</p>
<p>Maven定义了远端仓库，为了构建和开发的效率，防止频繁的网络传输，Maven又定义了本地仓库（Local Repo），用于缓存依赖。<code>mvn install</code>会将构件发布到本地仓库， <code>mvn deploy</code>会将构件发布到远端仓库。</p>
<p>有些企业内部存在大量的项目，有些项目开源，而有些项目是闭源的，企业并不想将项目构件提交到Maven中央仓库，此时，维护一个Maven中间仓库，并同时打通开发人员本地仓库对远端Maven中央仓库的依赖就有了很大的必要。<a href="http://www.sonatype.org/" target="_blank" rel="external">SonaType Nexus</a>就为此提供Maven中间仓库的服务实现。</p>
<h2 id="Maven最佳实践"><a href="#Maven最佳实践" class="headerlink" title="Maven最佳实践"></a>Maven最佳实践</h2><p>Maven的POM结构是树形层级依赖的，这些依赖就形成了配置的传递性，即在 <em>父POM</em> 中声明的配置，也会成为 <em>子POM</em> 的默认配置，<br>除非子POM重新定义这些配置。</p>
<p>另外，这里简单罗列几条Maven开发过程中的最佳实践，供参考：  </p>
<ol>
<li>对于复杂的系统，采用树形化的目录结构管理子系统和模块，层级深度最好不要超过4或5层。</li>
<li>系统的目录名最好与POM中的<code>&lt;artifactId&gt;</code>定义的系统/模块名称一致。</li>
<li><code>&lt;artifactId&gt;</code>定义的系统/模块名称尽量不要简写，推荐采用’-‘连接，或者采用包名称样式。</li>
<li>所有依赖的版本在顶层POM中声明，统归顶层POM维护，并将版本号归集到<code>&lt;properties&gt;</code>中。</li>
<li>采用<code>&lt;profile&gt;</code>定义系统的切面，减少项目开发时的构建时间，提高开发效率。</li>
<li>公共的插件配置归集到顶层POM中声明，统归顶层POM维护。</li>
<li>工程中依赖的公共资源文件集中到一起，通过依赖使用，减少因未同步修改导致的构建失败。</li>
</ol>
<p><strong>备注： 本文示例工程中的代码仅为了快速搭建和验证自动化IT，未很好的遵循上述最佳实践</strong></p>
<h2 id="Maven为IT自动化提供支持"><a href="#Maven为IT自动化提供支持" class="headerlink" title="Maven为IT自动化提供支持"></a>Maven为IT自动化提供支持</h2><p>通过一个命令即可实现工程的整个生命周期自动化执行，这是Maven的强大之处，也是实现IT自动化的重要支撑。Nexus仓库的存在，为构件的自动发布<br>管理与产品依赖的自动打包提供了基础。</p>
<h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><ul>
<li>Maven经过这么多年的发展，已经非常成熟。限于篇幅，本文只是从起源和概念上重新梳理了一边，让大家加深对Maven的认知，以便于体会Maven为软件自动化构建所做的支持。  </li>
<li>本文示例工程代码位于<a href="https://github.com/christtrc/greeter-osgi-example" target="_blank" rel="external">greeter-osgi-example</a>。</li>
<li>下一篇文章，我们将讲述源代码的管理即SCM，并在后续文章中讲述如何通过Maven实现源代码的版本自动化管理。</li>
</ul>
<h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul>
<li><a href="http://www.juvenxu.com/mvn-def-guide/" target="_blank" rel="external">Maven权威指南</a>  </li>
<li><a href="http://book.douban.com/subject/3182739/" target="_blank" rel="external">Maven The Definitive Guide</a></li>
</ul>

          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>


    <footer class="post-footer">
      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
  <link itemprop="mainEntityOfPage" href="http://chrisrc.me/2015/08/11/autoit-support-tools/">

  <span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <meta itemprop="name" content="chrisrc">
    <meta itemprop="description" content="">
    <meta itemprop="image" content="/images/avatar.gif">
  </span>

  <span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
    <meta itemprop="name" content="山中，山外与俯瞰">
    <span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject">
      <img style="display:none;" itemprop="url image" alt="山中，山外与俯瞰" src="">
    </span>
  </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2015/08/11/autoit-support-tools/" itemprop="url">
                  IT自动化(2)——“生产线”上的工具
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2015-08-11T14:32:15+08:00">
                2015-08-11
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
              <span class="post-meta-divider">|</span>
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/IT自动化/" itemprop="url" rel="index">
                    <span itemprop="name">IT自动化</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <a href="/2015/08/11/autoit-support-tools/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2015/08/11/autoit-support-tools/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          

          
          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="前文回顾"><a href="#前文回顾" class="headerlink" title="前文回顾"></a>前文回顾</h2><p>前文我们提出了一种如下图所示的实现IT自动化的解决方案。方案中，我们为整个IT自动化生产线的各个环节选择了一种特定<br>的生产工具。此方案以Java工程为实际案例，大部分环节对其它类型的工程也适用。本文将简要介绍这些工具的特征，后续文章，将用这些工具把IT自动化生产线装配并运转起来。</p>
<p><img src="/images/autoit_arch.png" alt="IT自动化架构"></p>
<h2 id="IT自动化工具集"><a href="#IT自动化工具集" class="headerlink" title="IT自动化工具集"></a>IT自动化工具集</h2><h3 id="工程构建工具"><a href="#工程构建工具" class="headerlink" title="工程构建工具"></a>工程构建工具</h3><p>软件技术发展到今天，对于各种语言来说，软件的编译过程基本上都变的很简单，像用于Java的<a href="http://maven.apache.org/" target="_blank" rel="external">Maven</a>或<br><a href="http://www.gradle.org/" target="_blank" rel="external">Grade</a>，用于Ruby的<a href="http://rake.rubyforge.org/" target="_blank" rel="external">Rake</a>，用于Scala的<a href="http://www.scala-sbt.org/" target="_blank" rel="external">SBT</a>，<br>用于Python的<a href="http://scons.org/" target="_blank" rel="external">Scons</a>，用于JavaScript的<a href="http://gulpjs.com/" target="_blank" rel="external">Gulp</a>或<a href="http://gruntjs.com/" target="_blank" rel="external">Grunt</a>等等。这些工具的发展和<br>成熟，成为IT自动化的基础。</p>
<p>Java构建世界中，Ant已经没落，Maven已经成熟，新兴的Gradle在展现其在Android自动编译领域的优势的同时还有很长的路要走。Java构件管理中<br>的两大阵营Ivy和Maven仓库，后者已经成为既定事实的标准。</p>
<p>Maven和Gradle都支持软件完整的生命周期，前者基于XML配置，后者在Groovy上构建的DSL。Gradle的定制能力强于Maven，至于选择，还是看<br>人员及项目适用性。</p>
<p><img src="/static/img/maven-logo-black-on-white.png" width="170" height="43" alt="Maven Logo" align="center"></p>
<p>本系列方案的示例采用Maven作为工程项目构建工具。</p>
<h3 id="集成开发工具（IDE）"><a href="#集成开发工具（IDE）" class="headerlink" title="集成开发工具（IDE）"></a>集成开发工具（IDE）</h3><p>集成开发工具对于每一种语言来说，都有一段值得诉说的历史，跌宕起伏，兴衰更替。<br>当前，仍被开发者们广泛使用的，包括从极客们推崇的Vim，Emacs，到文本编辑器Sublime Text, Atom, Notepad++，再到集成的IDE，如Eclipse，Netbeans，<br>微软的Visual Studio，Android Studio, 苹果iOS开发的Xcode，<br>提供商业化产品的Jetbrains全产品线：Intellij IDEA， WebStorm， RubyMine，PyCharm, PhpStorm，AppCode，…<br>等等等等，功能都在不断的强化，以适应语言的发展和现代应用开发的需求。</p>
<p><img src="/static/img/idea.png" width="40" height="40" alt="IDEA Logo" align="center"><br><img src="/static/img/eclipse-800x188.png" width="160" height="40" alt="Eclipse Logo" align="center"></p>
<p>用于Java开发的IDE中，Eclipse和Intellij IDEA是主流，Netbeans也还有很大的一部分用户基础。本系列方案的示例，采用Eclipse和IDEA作为<br>IDE工具。</p>
<h3 id="代码管理工具"><a href="#代码管理工具" class="headerlink" title="代码管理工具"></a>代码管理工具</h3><p>代码管理工具SCM从一开始就是为配合软件过程管理而生，从CVS，到SVN，VSS，ClearCase，再到Mercurial(hg)，Git，它们在软件开发过程中扮演<br>至关重要的角色。Git自为Linux内核源代码管理而生，以其分布式代码管理的特性逐渐替代其它SCM工具成为应用开发代码管理的主流。</p>
<p>Git工具的功能在变得越来越强大，客户端如<a href="https://git-for-windows.github.io/" target="_blank" rel="external">Git for Windows</a>，<a href="https://tortoisegit.org/" target="_blank" rel="external">TortoiseGit</a>，<a href="http://www.syntevo.com/smartgit/" target="_blank" rel="external">SmartGit</a>；服务器端如：<a href="https://about.gitlab.com/" target="_blank" rel="external">Gitlab</a>，Github Enterprise，Atlassian Stash；在线代码托管如：<a href="https://github.com/" target="_blank" rel="external">Github</a>，BitBucket，Gitcafe。</p>
<p><img src="/static/img/gitlab_logo.jpg" width="160" height="40" alt="Eclipse Logo" align="center"></p>
<p>本系列方案的示例，采用本地搭建的Gitlab作为SCM工具。</p>
<h3 id="代码审查工具"><a href="#代码审查工具" class="headerlink" title="代码审查工具"></a>代码审查工具</h3><p>代码审查工具是确保代码规范，减少代码潜在BUG的事前防御性工具，各种语言都有对应的代码检查工具存在，Java中常用的是Checkstyle，PMD，<br>用于JavaScript的JSLint等等，也有集成的代码审查管理平台如SonarQube，通过插件可以对不同语言的代码审查进行支持。详细列表可参考<br>开源中国<a href="http://www.oschina.net/project/tag/196/code-optimization" target="_blank" rel="external">代码审查分析优化工具列表</a></p>
<p><img src="/static/img/sonar.png" width="160" height="40" alt="Sonar Logo" align="center"></p>
<p>本系列方案的示例，采用SonarQube作为代码审查工具。</p>
<h3 id="需求与缺陷管理工具"><a href="#需求与缺陷管理工具" class="headerlink" title="需求与缺陷管理工具"></a>需求与缺陷管理工具</h3><p>需求与缺陷管理工具也是伴随着软件开发过程管理而生，特别是在RUP时代，需求分析在软件过程中所占的比重非常大。随着互联网，移动互联<br>和物联网的发展，敏捷开发，极限编程的运用，现代系统开发的节奏变得快速而且持续，需求与缺陷管理开始贯穿软件系统的整个生命周期。</p>
<p>当前，需求与缺陷管理工具中占据主流的如商业产品Atlassian Jira，Youtrack，开源的<a href="http://www.redmine.org/" target="_blank" rel="external">Redmine</a>， Bugzilla， Mantis， Trac等等。在线项目<br>管理工具也在不断发展，如国外的trello、asana、basecamp等，国内的有<a href="http://www.mingdao.com/" target="_blank" rel="external">明道</a>、worktile、tower、teambition等。</p>
<p><img src="/static/img/redmine_logo.jpg" width="130" height="40" alt="Redmine Logo" align="center"></p>
<p>本系列方案的示例，采用Redmine作为需求与缺陷管理工具。</p>
<h3 id="持续集成工具"><a href="#持续集成工具" class="headerlink" title="持续集成工具"></a>持续集成工具</h3><p>持续集成作为软件一种软件开发实践，通过经常性的集成，采用自动化的构建（包括编译，发布，测试)尽可能早的发现项目或产品的质量问题。<br>持续集成发展到现在，其目标已不单单是为了控制项目风险和解决质量问题，它已成为IT自动化过程中至关重要的核心环节。</p>
<p>常用的持续集成工具有Hudson，<a href="http://jenkins-ci.org/" target="_blank" rel="external">Jenkins</a>，<a href="http://www.jetbrains.com/teamcity/" target="_blank" rel="external">TeamCity</a>，<a href="http://continuum.apache.org/" target="_blank" rel="external">Apache Continuum</a>， <a href="http://www.atlassian.com/software/bamboo/" target="_blank" rel="external">Bamboo</a>，<br><a href="http://www.pmease.com/" target="_blank" rel="external">QuickBuild</a>，<a href="http://cruisecontrol.sourceforge.net/" target="_blank" rel="external">CruiseControl</a>，以及<br>基于云的持续集成工具<a href="https://travis-ci.org/" target="_blank" rel="external">Travis CI</a>等。</p>
<p><img src="/static/img/jenkins.png" width="48" height="48" alt="Redmine Logo" align="center"></p>
<p>本系列方案的示例，采用Redmine作为需求与缺陷管理工具。</p>
<h3 id="持续测试工具"><a href="#持续测试工具" class="headerlink" title="持续测试工具"></a>持续测试工具</h3><p>软件测试作为检测和控制产品质量的重要环节，各种工具和理论不断提出并实践，如TDD开发，以及支持TDD开发的众多单元测试工具：JUnit及<br>其他语言的Unit框架，TestNG，EasyMock等。</p>
<p>众多厂商都为软件测试提供了顶级的软件测试产品，如HP的QTP，IBM的Rational Robot。开源的集成测试工具如Selenium。<br>随着移动互联网的发展，移动端的测试工具也在不断壮大，如测试Android的Robotium， Appium， MonkeyRunner，UiAutomator等。</p>
<p>用于产品性能测试的工具如：Load Runner， Apache Jmeter， 重型、分布式多协议测试工具Tsung等。</p>
<p><img src="/static/img/selenium_logo.jpg" width="48" height="48" alt="Selenium Logo" align="center"></p>
<p>本系列方案的示例，采用Selenium作为持续测试工具。</p>
<h3 id="自动部署工具"><a href="#自动部署工具" class="headerlink" title="自动部署工具"></a>自动部署工具</h3><p>随着大数据，云计算和动辄成百上千台的服务器机群的出现，自动部署工具对于运维的重要性变得越来越重要，同时它也是打通开发团队与<br>最终用户的一道重要的桥梁。<br>常用的工具有基于YAML/SSH的<a href="http://www.ansible.com/" target="_blank" rel="external">Ansible</a>，基于Ruby的<a href="https://docs.chef.io/" target="_blank" rel="external">Chef</a>和<a href="https://puppetlabs.com/" target="_blank" rel="external">Puppet</a>，<br>基于Python的<a href="http://www.fabfile.org/" target="_blank" rel="external">Fabric</a>和<a href="http://saltstack.com/" target="_blank" rel="external">Saltstack</a>。</p>
<p><img src="/static/img/ansible.png" width="48" height="48" alt="Ansible Logo" align="center"></p>
<p>本系列方案的示例，采用Ansible作为自动部署工具。</p>
<h3 id="运营平台工具"><a href="#运营平台工具" class="headerlink" title="运营平台工具"></a>运营平台工具</h3><p>随着系统规模的不断扩大，系统资源整合并有效利用变的尤为重要，虚拟化技术为资源整合利用提供了支撑。而LXC、<a href="https://www.docker.com/" target="_blank" rel="external">Docker</a>等容器隔离技术<br>的发展，更是将持续部署的需求变为现实。</p>
<p>当前基于<a href="http://mesos.apache.org/" target="_blank" rel="external">Mesos</a>或<a href="http://kubernetes.io/" target="_blank" rel="external">Kubernetes</a>的集群管理结合Docker容器技术，成为持续部署的首选平台方案。</p>
<p><img src="/static/img/docker_logo.png" width="180" height="48" alt="Docker Logo" align="center"></p>
<p>本系列方案的示例，采用Docker作为运营平台的容器系统。</p>
<h3 id="反馈工具"><a href="#反馈工具" class="headerlink" title="反馈工具"></a>反馈工具</h3><p>现代系统中，产品在用户使用过程中，如何畅通的将反馈信息收集回来仍然是一个值得大力探索的领域。粉丝内测，论坛信息反馈，产品<br>反馈接口等渠道，反馈信息的收集，筛选，整理和最终形成需求导入，这些环节如何做到紧密衔接，也是IT自动化过程中的一大挑战。</p>
<p>类似<a href="https://www.uservoice.com/" target="_blank" rel="external">UserVoice</a>、<a href="http://userecho.com/" target="_blank" rel="external">UserEcho</a>的产品在收集用户反馈并快速响应方面为提供了一个很好的开始。</p>
<h3 id="其它工具"><a href="#其它工具" class="headerlink" title="其它工具"></a>其它工具</h3><p>随着集群部署成为常态，系统在本地的单机开发测试如何模拟集群环境也是影响开发效率的关键。通常基于虚拟机技术（Vmware，<br>Virtualbox，KVM等）可以满足基本的开发需求。但是限于单机硬件条件制约，虚拟机消耗的资源通常会比较多，通常会影响开发体验。</p>
<p><a href="https://www.vagrantup.com/" target="_blank" rel="external">Vagrant</a>是一个基于Ruby的工具，用于创建和部署虚拟化开发环境。<code>Vagrant + VM</code>，<code>Vagrant + VM + Docker</code>，<code>Vagrant + Docker</code>的方案可以快速搭建需要的集群开发环境，并自动管理虚拟机或容器，大大提升面对集群<br>环境的开发效率。</p>
<p><img src="/static/img/vagrant_logo.jpg" width="48" height="48" alt="Docker Logo" align="center"><br>+<br><img src="/static/img/virtualbox.png" width="48" height="48" alt="Docker Logo" align="center"><br>+<br><img src="/static/img/docker.png" width="48" height="48" alt="Docker Logo" align="center"></p>
<p>本系列方案的示例，采用Vagrant + VM/Docker的方式搭建本地开发测试环境。</p>
<h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><ul>
<li>本文简要列举了IT自动化生产线上各个环节的各种适用工具，仅供参考，在实际实践过程中，还需要检验和验证。限于篇幅和认知，<br>许多工具并未列举。</li>
<li>在后续文章中，我们将针对生产线上的各个环境开始具体讲述并串联起来。</li>
</ul>

          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>


    <footer class="post-footer">
      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
  <link itemprop="mainEntityOfPage" href="http://chrisrc.me/2015/08/10/autoit-intro/">

  <span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <meta itemprop="name" content="chrisrc">
    <meta itemprop="description" content="">
    <meta itemprop="image" content="/images/avatar.gif">
  </span>

  <span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
    <meta itemprop="name" content="山中，山外与俯瞰">
    <span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject">
      <img style="display:none;" itemprop="url image" alt="山中，山外与俯瞰" src="">
    </span>
  </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2015/08/10/autoit-intro/" itemprop="url">
                  IT自动化(1)——持续开发，持续集成，持续交付与持续部署
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2015-08-10T11:12:15+08:00">
                2015-08-10
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
              <span class="post-meta-divider">|</span>
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/IT自动化/" itemprop="url" rel="index">
                    <span itemprop="name">IT自动化</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <a href="/2015/08/10/autoit-intro/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2015/08/10/autoit-intro/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          

          
          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="提出问题"><a href="#提出问题" class="headerlink" title="提出问题"></a>提出问题</h2><p>&nbsp;&nbsp;软件构件从提出需求，进行构建再到应用部署是一个系统工程。<br>软件工程研究了很多年，随着理论，工具的不断成熟，我们所面对的应用环境也在不断发生变化，唯一不变的是软件工程管理要与当前需求环境相结合的实践要求。<br>生产过程的自动化已经被社会深刻接受并相当普及，软件过程中的自动化也有了前所未有的发展，并且在不断接受新环境新需求的实践检验。</p>
<p>&nbsp;&nbsp;IT自动化所追求的目标是开发人员实现功能，用户体验功能，乍一看，与通常的软件过程没多大不同，问题的关键就在于开发实现与用户体验之间的“鸿沟”。</p>
<p>&nbsp;&nbsp;传统软件过程中，这道“鸿沟”不仅需要漫长的过程，还需要众多的人力精细化分工并紧密协同。环节越多，人工参与的环节越多，出错的概率越大，用户真实的感受与开发人员面对的需求之间的差异就越大。<br>当前正处在信息工业革命的爆发期，系统需求环境与几年前又有很大的不同。几年前的系统只需要几台服务器，秒级响应，GB级别的数据存储；现在，用户开始要求毫秒级响应，数据以PB级别存储，系统规模也到了成百上千台服务器。</p>
<p>&nbsp;&nbsp;面对这种新环境，我们不仅要在系统架构设计原则上进行思考，同时也要思考如何缩短甚至消除横亘于在产品开发人员与最终用户之间的“鸿沟”。</p>
<h2 id="分析问题"><a href="#分析问题" class="headerlink" title="分析问题"></a>分析问题</h2><p>&nbsp;&nbsp;IT自动化是人与人之间通过“自动化IT生产线”紧密协同，高效生产的过程。</p>
<p>&nbsp;&nbsp;现代系统的自动化IT生产线与传统软件过程有本质区别，这主要体现在传统软件工程中的各个环节是割裂的，需要人来传递；<br>开发者面对的是整理好的需求设计，这先天是存在延迟的。</p>
<p><img src="/images/software_procedure_old.png" alt="传统软件过程"></p>
<p>&nbsp;&nbsp;现代软件系统开发中，开发者面对的就是最终用户反馈，中间的环节没有多余的人员参与。<br>这就必须要采取自动化的过程，打通开发开发者与最终用户间的通道。</p>
<p><img src="/images/software_procedure_new.png" alt="现代软件系统过程"></p>
<p>&nbsp;&nbsp;IT自动化包括持续开发和持续部署两部分。持续开发关注需求及缺陷的持续跟踪，代码的持续静态分析，发布前版本的持续测试。<br>持续部署是持续集成和持续交付向前演进的阶段，它以持续开发为基础。两者形成一个大的螺旋上升的闭环，最终为用户提供一个生态的活性的系统。</p>
<p>&nbsp;&nbsp;IT自动化涉及的环节包括：<em>需求依据，产品开发，代码静态审查，单元测试，集成测试，性能测试，开发版，开发版反馈，测试版发布，测试版反馈，<br>稳定版发布，稳定版反馈，最后再回到需求依据</em>。面对如此多的环节，开发团队面怎样才能及时的接收和高效的处理用户反馈？<br>这就是IT自动化所要解决的问题。</p>
<h2 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h2><p>&nbsp;&nbsp;实现IT过程自动化，必须<br>借助一组紧密衔接的IT基础工具，能够可靠的将实现的不同阶段（<em>开发版（development）</em>，<em>测试版（testing）</em>，<em>稳定版（stable）</em>）的产品功能<br>快速地传递给用户进行体验，同时将用户反馈快速的收集回来形成产品下一个迭代的依据。</p>
<p><img src="/images/autoit_arch.png" alt="IT自动化架构"></p>
<p>&nbsp;&nbsp;如上图所示，通过选取一组关注软件生命周期过程中各个环节的辅助工具，将它们打通，使得持续开发和持续部署过程得以实现。</p>
<p>&nbsp;&nbsp;IT自动化的过程是一个不断实践的过程，这个过程需要根据实际业务进行大量的调整。同时，在软件生命周期的各个环节，合适的工具不止一种，在具体实践过程中要根据自己的情况进行决策。</p>
<h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><p>&nbsp;&nbsp;本文及后续系列文章将向那些仍然只关注用单一语言解决单一问题的行业新人提供一个新的场景，让他们得以思考自己在这个自动化IT场景中所处的位置。<br>对于控制软件过程的管理者，本文及后续文章将向他们展示一种特定的自动化IT实践用作他们践行高效之路的参考。</p>

          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>


    <footer class="post-footer">
      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
  <link itemprop="mainEntityOfPage" href="http://chrisrc.me/2015/08/04/java-osgi-dynamic-app-with-karaf-deploy/">

  <span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <meta itemprop="name" content="chrisrc">
    <meta itemprop="description" content="">
    <meta itemprop="image" content="/images/avatar.gif">
  </span>

  <span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
    <meta itemprop="name" content="山中，山外与俯瞰">
    <span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject">
      <img style="display:none;" itemprop="url image" alt="山中，山外与俯瞰" src="">
    </span>
  </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2015/08/04/java-osgi-dynamic-app-with-karaf-deploy/" itemprop="url">
                  Apache Karaf构建动态模块化应用(6)--Karaf离线打包发布
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2015-08-04T12:15:45+08:00">
                2015-08-04
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
              <span class="post-meta-divider">|</span>
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/OSGi/" itemprop="url" rel="index">
                    <span itemprop="name">OSGi</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <a href="/2015/08/04/java-osgi-dynamic-app-with-karaf-deploy/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2015/08/04/java-osgi-dynamic-app-with-karaf-deploy/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          

          
          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p>在使用Apache Karaf进行实际打包发布时，基于Maven的自动依赖环境可能会制约产品的打包发布。因为出于安全要求，要部署运行的环境往往不能<br>随意访问远程的Maven仓库，这时就需要将产品运行所需要的所有Feature及Bundle等进行离线打包。</p>
<p>Karaf对OSGi Bundle的组织采用Pax的 <strong>maven url</strong> 方式，这也隐性的继承了maven的特性，即，所有的依赖来自maven仓库，<br>在实际开发中，这大大的便利了项目结构的组织和维护，开发人员只要指明对某个bundle的maven依赖，karaf自动去选取和下载。</p>
<p>本文对之前写的一篇博客进行了简单整理，作为本系列的一部分。</p>
<h2 id="Pax-URL-Mvn协议"><a href="#Pax-URL-Mvn协议" class="headerlink" title="Pax URL Mvn协议"></a>Pax URL Mvn协议</h2><p>在讨论karaf的maven依赖加载与管理之前，我们先了解一下<a href="https://ops4j1.jira.com/wiki/display/paxurl/Mvn+Protocol" target="_blank" rel="external">Pax URL</a>项目的Mvn协议：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">mvn-uri := &apos;mvn:&apos; [ repository-url &apos;!&apos; ] group-id &apos;/&apos; artifact-id [ &apos;/&apos; [version] [ &apos;/&apos; [type] [ &apos;/&apos; classifier ] ] ] ]  </div><div class="line">repository-url := &lt; rfc2396 uri &gt; ; an url that points to a maven 2 repository</div><div class="line">group-id := &lt; maven groupId &gt; ; group id of maven artifact</div><div class="line">artifact-id := &lt; maven artifactId &gt; ; artifact id of maven artifact</div><div class="line">version := &lt; maven version &gt; | &apos;LATEST&apos; | range ; version of maven artifact</div><div class="line">range := ( &apos;[&apos; | &apos;(&apos; ) version &apos;,&apos; version ( &apos;)&apos; | &apos;]&apos; )</div><div class="line">type := &lt; maven type&gt; ; type of maven artifact</div><div class="line">classifier := &lt; maven classifier&gt; ; maven artifact classifier</div></pre></td></tr></table></figure>
<p>假设项目需要依赖Pax Web的service-0.2.0-SNAPSHOT.jar,对应的Mvn协议示例如下：</p>
<ul>
<li>mvn:org.ops4j.pax.web.bundles/service</li>
<li>mvn:org.ops4j.pax.web.bundles/service/LATEST</li>
<li>mvn:org.ops4j.pax.web.bundles/service/0.2.0-SNAPSHOT</li>
<li>mvn:<a href="http://repository.ops4j.org/maven2!org.ops4j.pax.web.bundles/service/0.2.0" target="_blank" rel="external">http://repository.ops4j.org/maven2!org.ops4j.pax.web.bundles/service/0.2.0</a></li>
<li>mvn:file://c:/localRepo!org.ops4j.pax.web.bundles/service/0.2.0  # 从目录中加载</li>
<li>mvn:org.ops4j.pax.web/pax-web-features/3.0.4-SNAPSHOT/xml/features # 标识pax-web-features-3.0.4-SNAPSHOT-features.xml构件</li>
</ul>
<h3 id="协议要点"><a href="#协议要点" class="headerlink" title="协议要点"></a>协议要点</h3><ol>
<li>如果版本（version）未指定，将使用默认值“LATEST”，并从可用的Maven元数据（metadata）中解析最新的版本，maven metadata的示例如下：</li>
</ol>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div></pre></td><td class="code"><pre><div class="line">&lt;?xml version="1.0" encoding="UTF-8"?&gt;  </div><div class="line"><span class="tag">&lt;<span class="name">metadata</span> <span class="attr">modelVersion</span>=<span class="string">"1.1.0"</span>&gt;</span>  </div><div class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.ops4j.pax.web<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span>  </div><div class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>pax-web-features<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span>  </div><div class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.0.4-SNAPSHOT<span class="tag">&lt;/<span class="name">version</span>&gt;</span>  </div><div class="line">  <span class="tag">&lt;<span class="name">versioning</span>&gt;</span>  </div><div class="line">    <span class="tag">&lt;<span class="name">snapshot</span>&gt;</span>  </div><div class="line">      <span class="tag">&lt;<span class="name">timestamp</span>&gt;</span>20131113.170334<span class="tag">&lt;/<span class="name">timestamp</span>&gt;</span>  </div><div class="line">      <span class="tag">&lt;<span class="name">buildNumber</span>&gt;</span>2<span class="tag">&lt;/<span class="name">buildNumber</span>&gt;</span>  </div><div class="line">    <span class="tag">&lt;/<span class="name">snapshot</span>&gt;</span>  </div><div class="line">    <span class="tag">&lt;<span class="name">lastUpdated</span>&gt;</span>20131113170334<span class="tag">&lt;/<span class="name">lastUpdated</span>&gt;</span>  </div><div class="line">    <span class="tag">&lt;<span class="name">snapshotVersions</span>&gt;</span>  </div><div class="line">      <span class="tag">&lt;<span class="name">snapshotVersion</span>&gt;</span>  </div><div class="line">        <span class="tag">&lt;<span class="name">extension</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">extension</span>&gt;</span>  </div><div class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>3.0.4-20131113.170334-2<span class="tag">&lt;/<span class="name">value</span>&gt;</span>  </div><div class="line">        <span class="tag">&lt;<span class="name">updated</span>&gt;</span>20131113170334<span class="tag">&lt;/<span class="name">updated</span>&gt;</span>  </div><div class="line">      <span class="tag">&lt;/<span class="name">snapshotVersion</span>&gt;</span>  </div><div class="line">      <span class="tag">&lt;<span class="name">snapshotVersion</span>&gt;</span>  </div><div class="line">        <span class="tag">&lt;<span class="name">classifier</span>&gt;</span>features<span class="tag">&lt;/<span class="name">classifier</span>&gt;</span>  </div><div class="line">        <span class="tag">&lt;<span class="name">extension</span>&gt;</span>xml<span class="tag">&lt;/<span class="name">extension</span>&gt;</span>  </div><div class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>3.0.4-20131113.170334-2<span class="tag">&lt;/<span class="name">value</span>&gt;</span>  </div><div class="line">        <span class="tag">&lt;<span class="name">updated</span>&gt;</span>20131113170334<span class="tag">&lt;/<span class="name">updated</span>&gt;</span>  </div><div class="line">      <span class="tag">&lt;/<span class="name">snapshotVersion</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">snapshotVersions</span>&gt;</span>  </div><div class="line">  <span class="tag">&lt;/<span class="name">versioning</span>&gt;</span>  </div><div class="line"><span class="tag">&lt;/<span class="name">metadata</span>&gt;</span></div></pre></td></tr></table></figure>
<ol>
<li><p>如果version是SNAPSHOT版本，则采用与maven一致的策略来解析SNAPSHOT版本；</p>
</li>
<li><p>如果type未指定，默认值为JAR；</p>
</li>
<li><p>如果指定了一个type但没有指定version，则必须为version留有占位即：mvn:groups/artifact//type</p>
</li>
<li><p>Pax URL从0.3.0版本开始支持类别Classifier，如果类别classifier未指定，则不启用类别；</p>
</li>
<li><p>如果指定了类别，但没有指定版本version或类型type，则必须未版本和（或）类型留有占位，即：</p>
</li>
</ol>
<blockquote>
<p>mvn:groups/artifact///classifier</p>
</blockquote>
<p> 或</p>
<blockquote>
<p>mvn:groups/artifact/version//classifier</p>
</blockquote>
<p> 或</p>
<blockquote>
<p>mvn:groups/artifact//type/classifier</p>
</blockquote>
<h3 id="版本范围"><a href="#版本范围" class="headerlink" title="版本范围"></a>版本范围</h3><p>从0.2.0版本开始，Pax URL Mvn支持版本范围，示例如下</p>
<pre><code>- [1.2.3, 4.5.6) — 1.2.3 &lt;= x &lt; 4.5.6
- [1.2.3, 4.5.6] — 1.2.3 &lt;= x &lt;= 4.5.6
- (1.2.3, 4.5.6) — 1.2.3 &lt; x &lt; 4.5.6
- (1.2.3, 4.5.6] — 1.2.3 &lt; x &lt;= 4.5.6
</code></pre><h3 id="mvn协议的参数配置"><a href="#mvn协议的参数配置" class="headerlink" title="mvn协议的参数配置"></a>mvn协议的参数配置</h3><p>可以通过两种方式来配置Mvn协议：1）通过OSGi CM；2）通过框架/系统变量。通过CM配置的参数具有高优先级。</p>
<table>
<thead>
<tr>
<th style="text-align:left">参数名称</th>
<th style="text-align:left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"></td>
</tr>
</tbody>
</table>
<p>org.ops4j.pax.url.mvn.certificateCheck| optional; true/false if the SSL certificate check should be done. Default false.<br>org.ops4j.pax.url.mvn.globalUpdatePolicy| optional; 控制远程maven仓库的更新策略，maven通过本地POM的时间戳比对为依据。可选的策略包括：always, daily (default), interval:X (where X is an integer in minutes) or never.<br>org.ops4j.pax.url.mvn.localRepository| optional; 指向本地仓库目录的路径<br>org.ops4j.pax.url.mvn.repositories| optional; 以逗号分隔的仓库URL列表<br>org.ops4j.pax.url.mvn.defaultRepositories| optional; 以逗号分隔的默认仓库URL列表<br>org.ops4j.pax.url.mvn.settings| optional; 指向maven settings.xml的路径<br>org.ops4j.pax.url.mvn.proxySupport| optional; true/false if the proxy support is enabled . Default true.  </p>
<h3 id="Maven-Settings配置查找"><a href="#Maven-Settings配置查找" class="headerlink" title="Maven Settings配置查找"></a>Maven Settings配置查找</h3><p>如果有必要且maven settings.xml可用，Pax URL Mvn按如下步骤查找settings.xml：</p>
<ol>
<li>查找配置参数</li>
<li>如果未找到，查找 ${user.home}/.m2/settings.xml</li>
<li>如果未找到，查找 ${maven.home}/conf/settings.xml</li>
<li>如果未找到，查找 ${M2_HOME}/conf/settings.xml</li>
</ol>
<h3 id="Maven本地仓库的查找"><a href="#Maven本地仓库的查找" class="headerlink" title="Maven本地仓库的查找"></a>Maven本地仓库的查找</h3><p>Maven本地仓库的查找顺序如下：</p>
<ol>
<li>查找配置参数定义；</li>
<li>如果未找到，在settings.xml中进行查找</li>
<li>如果未找到，默认认为仓库位于${user.home}/.m2/repository.</li>
</ol>
<h3 id="远端Maven仓库的解析"><a href="#远端Maven仓库的解析" class="headerlink" title="远端Maven仓库的解析"></a>远端Maven仓库的解析</h3><p>Maven仓库的解析顺序如下:</p>
<ol>
<li>在配置参数中查找</li>
<li>在settings.xml中查找</li>
</ol>
<p>如果配置参数中 <strong>org.ops4j.pax.url.mvn.repositories</strong> 的值以’+’开始，则来自settings.xml中的仓库地址也将附加到此配置的仓库列表中。</p>
<h3 id="设定仓库包含release-snapshot"><a href="#设定仓库包含release-snapshot" class="headerlink" title="设定仓库包含release/snapshot"></a>设定仓库包含release/snapshot</h3><p>可以在参数配置的仓库URL中通过添加如下标识来指定仓库所含有的构件类型（不区分大小写）：</p>
<pre><code>启用snapshots — 添加 @snapshots
禁用releases — 添加 @noreleases
</code></pre><p>示例如下:</p>
<ul>
<li><a href="http://repository.ops4j.org" target="_blank" rel="external">http://repository.ops4j.org</a> ; 默认不包含任何标识，只查找releases, 不包括snapshots  </li>
<li><a href="http://repository.ops4j.org/mvn-snapshots@snapshots" target="_blank" rel="external">http://repository.ops4j.org/mvn-snapshots@snapshots</a> ; 同时在此仓库查找releases和snapshots  </li>
<li><a href="http://repository.ops4j.org/mvn-snapshots@snapshots@noreleases" target="_blank" rel="external">http://repository.ops4j.org/mvn-snapshots@snapshots@noreleases</a> ; 仅查找snapshots, 不查找releases  </li>
</ul>
<h3 id="默认仓库"><a href="#默认仓库" class="headerlink" title="默认仓库"></a>默认仓库</h3><p>在某些情况下，通过默认仓库配置，可以防止用户配置对下载构件造成影响。如果对 <strong>org.ops4j.pax.url.mvn.defaultRepositories</strong> 进行了设置，则Pax URL Mvn首先检查此参数设定的默认仓库列表，如果未找到，则继续查找本地仓库和其它在 <strong>org.ops4j.pax.url.mvn.repositories</strong> 中配置的仓库。</p>
<h2 id="Karaf中Maven仓库处理策略的配置"><a href="#Karaf中Maven仓库处理策略的配置" class="headerlink" title="Karaf中Maven仓库处理策略的配置"></a>Karaf中Maven仓库处理策略的配置</h2><h3 id="默认仓库处理策略"><a href="#默认仓库处理策略" class="headerlink" title="默认仓库处理策略"></a>默认仓库处理策略</h3><p>Karaf通过 <strong>OSGi CM（config admin）</strong> 服务对Pax URL Mvn协议处理进行参数配置，具体的配置是位于<code>${karaf.home}/etc</code>下的<br><code>org.ops4j.pax.url.mvn.cfg</code>文件：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div></pre></td><td class="code"><pre><div class="line">#org.ops4j.pax.url.mvn.certificateCheck=</div><div class="line"></div><div class="line">#org.ops4j.pax.url.mvn.settings=</div><div class="line"></div><div class="line">#org.ops4j.pax.url.mvn.localRepository=</div><div class="line"></div><div class="line">org.ops4j.pax.url.mvn.useFallbackRepositories=false</div><div class="line"></div><div class="line"># org.ops4j.pax.url.mvn.proxySupport=false</div><div class="line"></div><div class="line">org.ops4j.pax.url.mvn.defaultRepositories=\</div><div class="line">    file:$&#123;karaf.home&#125;/$&#123;karaf.default.repository&#125;@id=system.repository@snapshots, \</div><div class="line">    file:$&#123;karaf.data&#125;/kar@id=kar.repository@multi@snapshots, \</div><div class="line">    file:$&#123;karaf.base&#125;/$&#123;karaf.default.repository&#125;@id=child.system.repository@snapshots</div><div class="line"></div><div class="line"># Use the default local repo (e.g.~/.m2/repository) as a &quot;remote&quot; repo</div><div class="line">#org.ops4j.pax.url.mvn.defaultLocalRepoAsRemote=false</div><div class="line"></div><div class="line">org.ops4j.pax.url.mvn.repositories= \</div><div class="line">    http://repo1.maven.org/maven2@id=central, \</div><div class="line">    http://repository.springsource.com/maven/bundles/release@id=spring.ebr.release, \</div><div class="line">    http://repository.springsource.com/maven/bundles/external@id=spring.ebr.external, \</div><div class="line">    http://zodiac.springsource.com/maven/bundles/release@id=gemini, \</div><div class="line">    http://repository.apache.org/content/groups/snapshots-group@id=apache@snapshots@noreleases, \</div><div class="line">    https://oss.sonatype.org/content/repositories/snapshots@id=sonatype.snapshots.deploy@snapshots@noreleases, \</div><div class="line">    https://oss.sonatype.org/content/repositories/ops4j-snapshots@id=ops4j.sonatype.snapshots.deploy@snapshots@noreleases, \</div><div class="line">    http://repository.springsource.com/maven/bundles/external@id=spring-ebr-repository@snapshots@noreleases</div></pre></td></tr></table></figure>
<p><strong>下面我们来看一下如何通过调整此配置文件，使得Karaf不再依赖远程Maven仓库和本地Maven仓库，让Karaf发布包随意离线部署成为现实。</strong></p>
<p>首先我们来看一下在org.ops4j.pax.url.mvn.repositories配置中存在两个指向目录路径的仓库URL，即：</p>
<blockquote>
<p><code>file:${karaf.home}/${karaf.default.repository}@id=system.repository</code></p>
</blockquote>
<p> 和</p>
<blockquote>
<p><code>file:${karaf.data}/kar@id=kar.repository@multi。file:${karaf.home}/${karaf.default.repository}@id=system.repository</code></p>
</blockquote>
<p> 实际指向的是karaf安装目录下的 <strong>system目录</strong>（也可以根据需要自行调整，<code>karaf.default.repository</code>参数位于 <strong>etc/system.properties</strong> 文件中）；</p>
<p> <code>file:${karaf.data}/kar@id=kar.repository@multi</code>实际指向的是karaf安装目录下的 <strong>data/kar</strong> 目录。</p>
<h3 id="离线处理策略"><a href="#离线处理策略" class="headerlink" title="离线处理策略"></a>离线处理策略</h3><p>通过禁用其他仓库URL，只启用这两个位置仓库，则karaf发布程序即可实现离线部署。</p>
<p>上面的<code>org.ops4j.pax.url.mvn.cfg</code>文件按下面具体配置进行调整：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">org.ops4j.pax.url.mvn.settings=</div><div class="line">org.ops4j.pax.url.mvn.localRepository=file:$&#123;karaf.home&#125;/$&#123;karaf.default.repository&#125;@id=system.repository@snapshots</div><div class="line">org.ops4j.pax.url.mvn.defaultLocalRepoAsRemote=true</div><div class="line">org.ops4j.pax.url.mvn.repositories= \  </div><div class="line">    file:$&#123;karaf.home&#125;/$&#123;karaf.default.repository&#125;@id=system.repository@snapshots, \  </div><div class="line">    file:$&#123;karaf.data&#125;/kar@id=kar.repository@multi</div></pre></td></tr></table></figure></p>
<p>此模式下，Pax URL Mvn优先检查system仓库，如果不存在，则检查${user.home}/.m2下的配置，如果没有settings.xml和repository目录，则加载依赖失败。</p>
<p>在实际部署时，确保system仓库包含所有依赖的bundle即可。</p>
<p>通过此方案，如果发布包中的system目录包含了系统运行所需的所有依赖，则karaf将不再寻求从远程仓库加载依赖，从而实现离线部署。</p>
<h3 id="离线依赖自动打包"><a href="#离线依赖自动打包" class="headerlink" title="离线依赖自动打包"></a>离线依赖自动打包</h3><p><strong>通过上述方案实现karaf离线部署的同时产生了新的问题，如何确保system目录包含所有的依赖同时又不包含无用的冗余依赖？</strong></p>
<p>这个问题可以通过karaf-maven-plugin提供的 <strong>features-add-to-repository</strong> 目标获得解决。在打包部署时，系统自动将Feature里的Bundle打包到system目录下。<br>下面来看一下配置：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">plugin</span>&gt;</span>  </div><div class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.karaf.tooling<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span>  </div><div class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>karaf-maven-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span>  </div><div class="line">  <span class="tag">&lt;<span class="name">executions</span>&gt;</span>  </div><div class="line">      <span class="tag">&lt;<span class="name">execution</span>&gt;</span>  </div><div class="line">          <span class="tag">&lt;<span class="name">id</span>&gt;</span>install-kar<span class="tag">&lt;/<span class="name">id</span>&gt;</span>  </div><div class="line">          <span class="tag">&lt;<span class="name">phase</span>&gt;</span>compile<span class="tag">&lt;/<span class="name">phase</span>&gt;</span>  </div><div class="line">          <span class="tag">&lt;<span class="name">goals</span>&gt;</span>  </div><div class="line">            <span class="tag">&lt;<span class="name">goal</span>&gt;</span>install-kars<span class="tag">&lt;/<span class="name">goal</span>&gt;</span>  </div><div class="line">          <span class="tag">&lt;/<span class="name">goals</span>&gt;</span>  </div><div class="line">      <span class="tag">&lt;/<span class="name">execution</span>&gt;</span>  </div><div class="line">      <span class="tag">&lt;<span class="name">execution</span>&gt;</span>  </div><div class="line">          <span class="tag">&lt;<span class="name">id</span>&gt;</span>features-add-to-repo<span class="tag">&lt;/<span class="name">id</span>&gt;</span>  </div><div class="line">          <span class="tag">&lt;<span class="name">phase</span>&gt;</span>generate-resources<span class="tag">&lt;/<span class="name">phase</span>&gt;</span>  </div><div class="line">          <span class="tag">&lt;<span class="name">goals</span>&gt;</span>  </div><div class="line">              features-add-to-repository</div><div class="line">          <span class="tag">&lt;/<span class="name">goals</span>&gt;</span>  </div><div class="line">          <span class="tag">&lt;<span class="name">configuration</span>&gt;</span>  </div><div class="line">              <span class="tag">&lt;<span class="name">descriptors</span>&gt;</span>  </div><div class="line">                  <span class="tag">&lt;<span class="name">descriptor</span>&gt;</span>mvn:org.apache.karaf.features/standard/$&#123;karaf.version&#125;/xml/features<span class="tag">&lt;/<span class="name">descriptor</span>&gt;</span>  </div><div class="line">                  <span class="tag">&lt;<span class="name">descriptor</span>&gt;</span>mvn:org.apache.karaf.features/spring/$&#123;karaf.version&#125;/xml/features<span class="tag">&lt;/<span class="name">descriptor</span>&gt;</span></div><div class="line">                  ……</div><div class="line">              <span class="tag">&lt;/<span class="name">descriptors</span>&gt;</span>  </div><div class="line">              <span class="tag">&lt;<span class="name">features</span>&gt;</span>  </div><div class="line">                  <span class="tag">&lt;<span class="name">feature</span>&gt;</span>http<span class="tag">&lt;/<span class="name">feature</span>&gt;</span></div><div class="line">                  <span class="tag">&lt;<span class="name">feature</span>&gt;</span>spring<span class="tag">&lt;/<span class="name">feature</span>&gt;</span></div><div class="line">                  …  </div><div class="line">              <span class="tag">&lt;/<span class="name">features</span>&gt;</span>  </div><div class="line">              <span class="tag">&lt;<span class="name">repository</span>&gt;</span>target/assembly/system<span class="tag">&lt;/<span class="name">repository</span>&gt;</span></div><div class="line">          <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span>  </div><div class="line">      <span class="tag">&lt;/<span class="name">execution</span>&gt;</span>  </div><div class="line">      <span class="tag">&lt;<span class="name">execution</span>&gt;</span>  </div><div class="line">          <span class="tag">&lt;<span class="name">id</span>&gt;</span>package<span class="tag">&lt;/<span class="name">id</span>&gt;</span>  </div><div class="line">          <span class="tag">&lt;<span class="name">goals</span>&gt;</span>  </div><div class="line">              <span class="tag">&lt;<span class="name">goal</span>&gt;</span>instance-create-archive<span class="tag">&lt;/<span class="name">goal</span>&gt;</span>  </div><div class="line">          <span class="tag">&lt;/<span class="name">goals</span>&gt;</span>  </div><div class="line">      <span class="tag">&lt;/<span class="name">execution</span>&gt;</span>  </div><div class="line">  <span class="tag">&lt;/<span class="name">executions</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></div></pre></td></tr></table></figure></p>
<p>通过此配置，系统在打包时，自动将karaf的standard feature库中的http feature及其依赖和spring feature库中的spring feature及其依赖下载到system目录中一起打包发布。</p>
<h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><p>通过上述方案，我们即可实现基于Karaf的项目自动打包、测试及发布。</p>

          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>


    <footer class="post-footer">
      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
  <link itemprop="mainEntityOfPage" href="http://chrisrc.me/2015/08/03/java-osgi-dynamic-app-with-karaf-dev/">

  <span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <meta itemprop="name" content="chrisrc">
    <meta itemprop="description" content="">
    <meta itemprop="image" content="/images/avatar.gif">
  </span>

  <span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
    <meta itemprop="name" content="山中，山外与俯瞰">
    <span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject">
      <img style="display:none;" itemprop="url image" alt="山中，山外与俯瞰" src="">
    </span>
  </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2015/08/03/java-osgi-dynamic-app-with-karaf-dev/" itemprop="url">
                  Apache Karaf构建动态模块化应用(5)--基于Maven快速搭建Karaf调试环境
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2015-08-03T21:05:26+08:00">
                2015-08-03
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
              <span class="post-meta-divider">|</span>
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/OSGi/" itemprop="url" rel="index">
                    <span itemprop="name">OSGi</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <a href="/2015/08/03/java-osgi-dynamic-app-with-karaf-dev/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2015/08/03/java-osgi-dynamic-app-with-karaf-dev/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          

          
          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p>前述文章介绍过Bndtools使得OSGi开发变得简单，高效。Bndtools适合在模块开发阶段，本文主要探讨在集成开发阶段<br>如何快速搭建基于maven的自定义的karaf开发调试环境，对于想对karaf的配置环境进行自定义和裁剪的开发人员可以参考此方案。</p>
<p>Apache Karaf项目在基于OSGi的组件框架应用开发中为开发者和架构师提供了一个便利的基础运行和部署框架。通过Karaf的Feature定义及Kar打包，<br>开发者可以自由的定义OSGi Bundle的分组并按需定制细粒度的打包定义，在系统发布时，通过自由组合这些feature及kar，<br>可以快速发布针对性的产品或特定的发布包。</p>
<p>本文对之前写的一篇博客进行了简单整理，作为本系列的一部分。</p>
<h2 id="Karaf的Feature定义"><a href="#Karaf的Feature定义" class="headerlink" title="Karaf的Feature定义"></a>Karaf的Feature定义</h2><p>Karaf的Feature概念可以看作是一个系统的子系统实现。我们知道OSGi是基于Bundle和Service进行开发的，对于Bundle的粒度控制需要开发人员根据项目和系统功能凭借经验自己控制。在一个大的系统中，可能存在成百上千的Bundle，这么多Bundle如果聚合在一起，如何区分和维护将是一个巨大的挑战，这往往导致一些开发人员和架构师对OSGi模块化望而却步。</p>
<p>而通过Karaf的Feature定义，最小单元的OSGi Bundle可以根据功能部分聚合在一起形成一个功能Feature，多个Feature可以聚合在一起形成一个大的Feature，最终所有的OSGi Bundle就有序的组合起来，就可以形成清晰的，可重复利用的一个个功能Feature，实现系统的真正模块化开发和组件的重复利用。如下图所示：</p>
<p><img src="/images/java_osgi_karaf_2_features.png" alt="Karaf Feature"></p>
<h3 id="Karaf中的Feature"><a href="#Karaf中的Feature" class="headerlink" title="Karaf中的Feature"></a>Karaf中的Feature</h3><p>Karaf提供了丰富的Feature功能：</p>
<ul>
<li>framework-${KARAF_VERSION}-features.xml 定义了框架的Feature</li>
<li>standard-${KARAF_VERSION}-features.xml 定义了基础的Feature，包括：<ul>
<li>feature</li>
<li>shell</li>
<li>deployer</li>
<li>wrapper</li>
<li>obr</li>
<li>bundle</li>
<li>config</li>
<li>jaas</li>
<li>log</li>
<li>http</li>
<li>http-whiteboard</li>
<li>kar</li>
<li>webconsole</li>
<li>ssh</li>
<li>scr</li>
</ul>
</li>
<li>enterprise-${KARAF_VERSION}-features.xml 定义了支持J2EE应用的Feature<ul>
<li>transaction</li>
<li>jpa</li>
<li>openjpa</li>
<li>hibernate</li>
<li>eclipselink</li>
<li>jdbc</li>
<li>jms</li>
<li>jndi</li>
</ul>
</li>
<li>spring-${KARAF_VERSION}-features.xml 定义了Spring框架的支持</li>
<li>pax-web-features-${PAX_VERSION}-features.xml 定义了Pax Web的支持</li>
</ul>
<h3 id="Feature定义"><a href="#Feature定义" class="headerlink" title="Feature定义"></a>Feature定义</h3><p>现在，我们来看一个Karaf的Feature定义：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">feature</span> <span class="attr">name</span>=<span class="string">"spring"</span> <span class="attr">description</span>=<span class="string">"Spring 3.2.x support"</span> <span class="attr">version</span>=<span class="string">"3.2.11.RELEASE_1"</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">bundle</span> <span class="attr">start-level</span>=<span class="string">"30"</span> <span class="attr">dependency</span>=<span class="string">"true"</span>&gt;</span>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.aopalliance/1.0_6<span class="tag">&lt;/<span class="name">bundle</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">bundle</span> <span class="attr">start-level</span>=<span class="string">"30"</span>&gt;</span>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-core/3.2.11.RELEASE_1<span class="tag">&lt;/<span class="name">bundle</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">bundle</span> <span class="attr">start-level</span>=<span class="string">"30"</span>&gt;</span>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-expression/3.2.11.RELEASE_1<span class="tag">&lt;/<span class="name">bundle</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">bundle</span> <span class="attr">start-level</span>=<span class="string">"30"</span>&gt;</span>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-beans/3.2.11.RELEASE_1<span class="tag">&lt;/<span class="name">bundle</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">bundle</span> <span class="attr">start-level</span>=<span class="string">"30"</span>&gt;</span>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-aop/3.2.11.RELEASE_1<span class="tag">&lt;/<span class="name">bundle</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">bundle</span> <span class="attr">start-level</span>=<span class="string">"30"</span>&gt;</span>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-context/3.2.11.RELEASE_1<span class="tag">&lt;/<span class="name">bundle</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">bundle</span> <span class="attr">start-level</span>=<span class="string">"30"</span>&gt;</span>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-context-support/3.2.11.RELEASE_1<span class="tag">&lt;/<span class="name">bundle</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">conditional</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">condition</span>&gt;</span>deployer<span class="tag">&lt;/<span class="name">condition</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">bundle</span> <span class="attr">start-level</span>=<span class="string">"30"</span>&gt;</span>mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.spring/4.0.0<span class="tag">&lt;/<span class="name">bundle</span>&gt;</span></div><div class="line">        <span class="tag">&lt;/<span class="name">conditional</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">feature</span>&gt;</span></div></pre></td></tr></table></figure>
<p>此Feature定义了Spring 3.2.x版本，启用此feature，我们可以像SSH框架那样在OSGi Bundle中基于Spring进行开发，不存在迁移成本。在Karaf运行时，<br>如果安装了此Feature，系统会自动启动Feature中定义的Bundle集合。Bundle的查找顺序是：本地system目录下的Bundle—&gt;本地Maven仓库—&gt;远端Maven仓库。</p>
<h2 id="使用Karaf-Kar进行打包"><a href="#使用Karaf-Kar进行打包" class="headerlink" title="使用Karaf Kar进行打包"></a>使用Karaf Kar进行打包</h2><p>Karaf的Kar打包功能存在于karaf的karaf-maven-plugin插件中。通过此插件，karaf可以将featue定义中的所有bundle及其依赖打包到一个以.kar为后缀的压缩文件中，形成可发布的组件包。通过karaf-maven-plugin插件与maven打包相关的其它插件配合，用户可以自由定义发布包的结构。</p>
<p>对于多个已定义的kar分发包，通过maven依赖，可以在一个最终的maven发布工程中打包在一起，形成一个产品的发布包。如下图所示：</p>
<p><img src="/images/java_osgi_karaf_2_kar.png" alt="Karaf Kar"></p>
<p>关于Karaf的karaf-maven-plugin插件，请参考<a href="http://karaf.apache.org/manual/latest/developers-guide/karaf-maven-plugin.html" target="_blank" rel="external">官方文档</a></p>
<h2 id="搭建Karaf自定义调试环境"><a href="#搭建Karaf自定义调试环境" class="headerlink" title="搭建Karaf自定义调试环境"></a>搭建Karaf自定义调试环境</h2><p>下面简要讲述一下基于maven的Karaf自定义调试环境的搭建过程。</p>
<p>通常，基于OSGi的开发，推荐使用 <strong>Eclipse+Bndtools</strong> 的插件开发环境。对于集成调试，基于maven的OSGi插件开发<br>（Bndtools的<a href="https://github.com/bndtools/bnd/tree/master/bnd-maven-plugin" target="_blank" rel="external">bnd-maven-plugin</a>插件和Felix的<a href="http://felix.apache.org/documentation/subprojects/apache-felix-maven-bundle-plugin-bnd.html" target="_blank" rel="external">maven-bundle-plugin</a>插件）同样方便、快速和高效，而且不受IDE开发环境的限制。</p>
<p>基于maven的OSGi开发，这里推荐使用Netbeans IDE（根据个人喜好），Netbeans对maven项目具有原生支持，可以自动解析maven的pom构建工程。</p>
<p>对于一个多模块的Maven OSGi项目(参考<a href="">karaf-osgi-app</a>)，构建一个<code>launcher</code>子模块，其pom.xml按如下定义：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div><div class="line">112</div><div class="line">113</div><div class="line">114</div><div class="line">115</div><div class="line">116</div><div class="line">117</div><div class="line">118</div><div class="line">119</div><div class="line">120</div></pre></td><td class="code"><pre><div class="line">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</div><div class="line"><span class="tag">&lt;<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">"http://maven.apache.org/POM/4.0.0"</span> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span> <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="name">modelVersion</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">parent</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>karaf<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>ossu.sandbox.karaf<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.0.0-SNAPSHOT<span class="tag">&lt;/<span class="name">version</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">parent</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>ossu.sandbox.karaf<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>karaf.launcher<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">packaging</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">packaging</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">name</span>&gt;</span>Ossu Sandbox :: Karaf :: Launcher<span class="tag">&lt;/<span class="name">name</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">description</span>&gt;</span>Run karaf instance or debug karaf instance<span class="tag">&lt;/<span class="name">description</span>&gt;</span></div><div class="line"></div><div class="line">    <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.karaf.features<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>framework<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">type</span>&gt;</span>kar<span class="tag">&lt;/<span class="name">type</span>&gt;</span></div><div class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.karaf.features<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>standard<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">classifier</span>&gt;</span>features<span class="tag">&lt;/<span class="name">classifier</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">type</span>&gt;</span>xml<span class="tag">&lt;/<span class="name">type</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">scope</span>&gt;</span>runtime<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></div><div class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.karaf.features<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">classifier</span>&gt;</span>features<span class="tag">&lt;/<span class="name">classifier</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">type</span>&gt;</span>xml<span class="tag">&lt;/<span class="name">type</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">scope</span>&gt;</span>runtime<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></div><div class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></div><div class="line"></div><div class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>ossu.sandbox.karaf<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>karaf.boilerplate.framework<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">type</span>&gt;</span>kar<span class="tag">&lt;/<span class="name">type</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;project.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></div><div class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></div><div class="line"></div><div class="line">    <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></div><div class="line"></div><div class="line">    <span class="tag">&lt;<span class="name">build</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.karaf.tooling<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>karaf-maven-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">executions</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;<span class="name">execution</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">id</span>&gt;</span>process-resources<span class="tag">&lt;/<span class="name">id</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">phase</span>&gt;</span>process-resources<span class="tag">&lt;/<span class="name">phase</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">goals</span>&gt;</span></div><div class="line">                            <span class="tag">&lt;<span class="name">goal</span>&gt;</span>install-kars<span class="tag">&lt;/<span class="name">goal</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;/<span class="name">goals</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;/<span class="name">execution</span>&gt;</span></div><div class="line">                <span class="tag">&lt;/<span class="name">executions</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;<span class="name">installedFeatures</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">feature</span>&gt;</span>wrapper<span class="tag">&lt;/<span class="name">feature</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;/<span class="name">installedFeatures</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;<span class="name">bootFeatures</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">feature</span>&gt;</span>framework<span class="tag">&lt;/<span class="name">feature</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">feature</span>&gt;</span>standard<span class="tag">&lt;/<span class="name">feature</span>&gt;</span></div><div class="line">                        <span class="comment">&lt;!--&lt;feature&gt;obr&lt;/feature&gt;--&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">feature</span>&gt;</span>region<span class="tag">&lt;/<span class="name">feature</span>&gt;</span></div><div class="line">                        <span class="comment">&lt;!--&lt;feature&gt;spring&lt;/feature&gt;--&gt;</span></div><div class="line">                    <span class="tag">&lt;/<span class="name">bootFeatures</span>&gt;</span></div><div class="line">                <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></div><div class="line">            <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></div><div class="line"></div><div class="line">            <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.codehaus.mojo<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>exec-maven-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">executions</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;<span class="name">execution</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">goals</span>&gt;</span></div><div class="line">                            <span class="tag">&lt;<span class="name">goal</span>&gt;</span>exec<span class="tag">&lt;/<span class="name">goal</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;/<span class="name">goals</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;/<span class="name">execution</span>&gt;</span></div><div class="line">                <span class="tag">&lt;/<span class="name">executions</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;<span class="name">executable</span>&gt;</span>java<span class="tag">&lt;/<span class="name">executable</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;<span class="name">workingDirectory</span>&gt;</span>$&#123;project.basedir&#125;/target/assembly<span class="tag">&lt;/<span class="name">workingDirectory</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;<span class="name">arguments</span>&gt;</span></div><div class="line"></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-classpath<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>$&#123;project.basedir&#125;/target/assembly/conf$&#123;path.separator&#125;$&#123;project.basedir&#125;/target/assembly/lib/karaf-jaas-boot.jar$&#123;path.separator&#125;$&#123;project.basedir&#125;/target/assembly/lib/karaf-jmx-boot.jar$&#123;path.separator&#125;$&#123;project.basedir&#125;/target/assembly/lib/karaf-org.osgi.core.jar$&#123;path.separator&#125;$&#123;project.basedir&#125;/target/assembly/lib/karaf.jar<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Xmx512m<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-XX:MaxPermSize=512m<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line"></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Dkaraf.startRemoteShell=true<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Djava.net.preferIPv4Stack=true<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Dderby.system.home=$&#123;project.basedir&#125;/target/assembly/data/derby<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Dderby.storage.fileSyncTransactionLog=true<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Dcom.sun.management.jmxremote<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Dkaraf.startLocalConsole=true<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Djline.WindowsTerminal.directConsole=false<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Dkaraf.home=$&#123;project.basedir&#125;/target/assembly<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Dkaraf.base=$&#123;project.basedir&#125;/target/assembly<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Dkaraf.etc=$&#123;project.basedir&#125;/target/assembly/etc<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Dkaraf.instances=$&#123;project.basedir&#125;/target/assembly/instances<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Djava.io.tmpdir=$&#123;project.basedir&#125;/target/assembly/data/tmp<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Djava.endorsed.dirs=$&#123;project.basedir&#125;/target/assembly/lib/endorsed<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Dkaraf.data=$&#123;project.basedir&#125;/target/assembly/data<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Djava.util.logging.config.file=$&#123;project.basedir&#125;/target/assembly/etc/java.util.logging.properties<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line"></div><div class="line">                        <span class="comment">&lt;!-- Debug configuration --&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Xdebug<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Djava.compiler=NONE<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line"></div><div class="line">                        <span class="tag">&lt;<span class="name">argument</span>&gt;</span>org.apache.karaf.main.Main<span class="tag">&lt;/<span class="name">argument</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;/<span class="name">arguments</span>&gt;</span></div><div class="line">                <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></div><div class="line">            <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></div><div class="line">        <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">build</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">project</span>&gt;</span></div></pre></td></tr></table></figure></p>
<p>通过这个pom定义，我们就可以在maven环境中启动karaf并进行调试。下面做一下详细说明：</p>
<h3 id="依赖部分"><a href="#依赖部分" class="headerlink" title="依赖部分"></a>依赖部分</h3><p>主要包括对karaf Framework kar的依赖，这是karaf框架的kar发布包，通过对其依赖，在运行时，Karaf的基础目录结构将被创建（位于该pom所在工程的target/assembly下）；<br>对karaf的<code>standard Feature</code>库和<code>spring feature</code>库进行依赖，通过对这两个feature库进行依赖，karaf在运行时可以知道到这两个feature库中查找具体的feature定义<br>对o<code>ssu.sandbox.karaf:karaf.boilerplate.framework</code>这个kar工程的依赖（这个kar是对karaf的具体裁剪，后面会讲到）。</p>
<h3 id="编译运行部分"><a href="#编译运行部分" class="headerlink" title="编译运行部分"></a>编译运行部分</h3><p>编译运行部分主要包括两个maven插件：karaf-maven-plugin和exec-maven-plugin。</p>
<ul>
<li><p>karaf-maven-plugin<br>此插件对依赖（jar、kar等）进行打包，生成发布kar包，并可以指定启动哪些feature</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">bootFeatures</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">feature</span>&gt;</span>framework<span class="tag">&lt;/<span class="name">feature</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">feature</span>&gt;</span>standard<span class="tag">&lt;/<span class="name">feature</span>&gt;</span></div><div class="line">  <span class="comment">&lt;!--&lt;feature&gt;obr&lt;/feature&gt;--&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">feature</span>&gt;</span>region<span class="tag">&lt;/<span class="name">feature</span>&gt;</span></div><div class="line">  <span class="comment">&lt;!--&lt;feature&gt;spring&lt;/feature&gt;--&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">bootFeatures</span>&gt;</span></div></pre></td></tr></table></figure>
</li>
<li><p>exec-maven-plugin</p>
</li>
</ul>
<p>此插件用于在maven工程中启动一个java虚拟机，此处主要是配置了karaf的启动参数并通过org.apache.karaf.main.Main入口启动Karaf。</p>
<h3 id="启动Karaf"><a href="#启动Karaf" class="headerlink" title="启动Karaf"></a>启动Karaf</h3><p>命令行环境下输入：</p>
<blockquote>
<p>mvn clean package exec:exec</p>
</blockquote>
<p>运行效果如下图所示：</p>
<p><img src="/images/java_osgi_karaf_2_mvn_exec.png" alt="Karaf Launcher"></p>
<p>在Netbeans IDE环境中启动执行，如下图所示，右键点击工程，在弹出菜单中选择定制——目标：</p>
<p><img src="/images/java_osgi_karaf_2_netbeans.png" alt="Karaf Netbeans"></p>
<p>在弹出窗口中输入：  </p>
<blockquote>
<p>clean package exec:exec</p>
</blockquote>
<p><img src="/images/java_osgi_karaf_2_netbeans_2.png" alt="Karaf Netbeans Run"></p>
<p>点击“确定”，执行效果如下图所示：</p>
<p><img src="/images/java_osgi_karaf_2_netbeans_3.png" alt="Karaf Netbeans Run"></p>
<h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><ul>
<li><p>限于篇幅，对于karaf的裁剪和自定义，将在后续文章中探讨。</p>
</li>
<li><p>karaf启动时开启了5005调试端口，可以连接上进行代码调试</p>
</li>
<li><p>此示例工程代码位于github的<a href="https://github.com/chrisrc/karaf-osgi-app" target="_blank" rel="external">karaf-osgi-app</a>。</p>
</li>
</ul>

          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>


    <footer class="post-footer">
      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
  <link itemprop="mainEntityOfPage" href="http://chrisrc.me/2015/08/02/java-osgi-dynamic-app-with-karaf/">

  <span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <meta itemprop="name" content="chrisrc">
    <meta itemprop="description" content="">
    <meta itemprop="image" content="/images/avatar.gif">
  </span>

  <span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
    <meta itemprop="name" content="山中，山外与俯瞰">
    <span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject">
      <img style="display:none;" itemprop="url image" alt="山中，山外与俯瞰" src="">
    </span>
  </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2015/08/02/java-osgi-dynamic-app-with-karaf/" itemprop="url">
                  Apache Karaf构建动态模块化应用(4)--了解Apache Karaf
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2015-08-02T22:12:36+08:00">
                2015-08-02
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
              <span class="post-meta-divider">|</span>
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/OSGi/" itemprop="url" rel="index">
                    <span itemprop="name">OSGi</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <a href="/2015/08/02/java-osgi-dynamic-app-with-karaf/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2015/08/02/java-osgi-dynamic-app-with-karaf/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          

          
          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="说在前面"><a href="#说在前面" class="headerlink" title="说在前面"></a>说在前面</h2><p>基于J2EE的开发在企业应用中之所以如此普及，这是与J2EE定义了Web容器，开发者只需要关注核心业务实现是分不开的。例如，用户应用开发完成，<br>只需放到Tomcat的Webapp中，启动Tomcat就可以运行查看业务效果。</p>
<p>同样的问题，在基于OSGi的开发中，为了简化系统的复杂性，我们在开发阶段通过模块化创建了大量的Bundle，如何让这些由不同人员开发，<br>甚至是分散在不同团队开发的Bundle可以很容易的聚合在一起，测试，运行和打包发布？下面我们来看如何通过<a href="http://karaf.apache.org" target="_blank" rel="external">Apache Karaf</a>实现前述需求。</p>
<h2 id="Apache-Karaf"><a href="#Apache-Karaf" class="headerlink" title="Apache Karaf"></a>Apache Karaf</h2><p>通常，一个可部署的系统应该包括：<br>启动停止的控制脚本<br>运行系统所需的参数配置文件<br>可部署的业务构件<br>系统运行时的日志服务<br>系统运行时的监控服务<br>支持系统进行横向扩展的集群能力等</p>
<p>仍以Tomcat为例，可以看出Tomcat很好的提供了上述功能。</p>
<p>下述将简要罗列一下Karaf提供的基本功能特性。</p>
<h3 id="Karaf特性"><a href="#Karaf特性" class="headerlink" title="Karaf特性"></a>Karaf特性</h3><p>Apache Karaf为基于OSGi的应用在开发，运行调试，测试，部署和生产环境运维等各个环节提供了支持。<br>结合OSGi的动态特性，Karaf为基于OSGi Bundle构件提供了：<br>灵活的配置和部署<br>基于“Feature”的应用构建<br>轻量级模块化，按需供应<br>高级的日志服务<br>动态的参数配置<br>命令行管理与控制<br>远程管理<br>支持不同的OSGi框架<br>通过Feature提供大量的基础服务<br><img src="/images/java_osgi_karaf_framework.png" alt="Karaf Framework"></p>
<h3 id="Karaf目录结构"><a href="#Karaf目录结构" class="headerlink" title="Karaf目录结构"></a>Karaf目录结构</h3><pre><code>|
+---bin                   : Startup scripts and commands
+---data                 : Karaf work directory
      | +---cache         : Installed bundles
      | +---log           : Default log directory
      | +---tmp           : Temporary files
+---deploy               : Directory for file system deployment
+---etc                   : Configuration files
+---instances           : Instance management
+---lib                   : Core libraries
+---system               : System bundle repository
</code></pre><p><strong>etc</strong> 目录存放系统及业务Bundle的配置参数。</p>
<p><strong>system</strong> 目录存放的是遵循Maven仓库结构的Bundle仓库。</p>
<h3 id="Karaf环境变量"><a href="#Karaf环境变量" class="headerlink" title="Karaf环境变量"></a>Karaf环境变量</h3><table>
<thead>
<tr>
<th style="text-align:left">变量</th>
<th style="text-align:left">说明</th>
<th style="text-align:left">默认值</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"></td>
</tr>
</tbody>
</table>
<p>KARAF_HOME|Karaf的安装路径|根据启动脚本的位置计算<br>KARAF_BASE|    Karaf的base路径|    KARAF_HOME<br>KARAF_DATA|    存储运行时数据的路径|    KARAF_BASE/data<br>KARAF_ETC|    配置文件的存储路径|    KARAF_BASE/etc<br>KARAF_OPTS|    传递给Java命令行参数|<br>KARAF_DEBUG|    如果值为‘true’，启动调试模式|  </p>
<h3 id="Karaf的控制台"><a href="#Karaf的控制台" class="headerlink" title="Karaf的控制台"></a>Karaf的控制台</h3><p><code>KARAF_HOME/bin/</code>目录下存放着Karaf的控制脚本，执行<code>karaf</code> 或者 <code>karaf.bat</code>启动Karaf服务框架:<br><img src="/images/java_osgi_karaf_console.png" alt="Karaf Console"></p>
<p>Karaf控制台提供了大量的命令，用户可以很容易的为自己的项目提供自定义命令（具体参考本系列中的 <strong>greeter-client</strong> 工程）。</p>
<ul>
<li>bundle:* - Install and control bundles</li>
<li>dev:* - Development support</li>
<li>feature:* - Manage features</li>
<li>instance:* - Control of multiple instances</li>
<li>jaas:* - JAAS role and rights management</li>
<li>log:* - log display</li>
<li>obr:* - Interaction with OSGi Bundle Repositories</li>
<li>scr:* - Declarative Services management</li>
<li>service:* - Manage OSGi Services</li>
<li>shell:* - useful helper functions (i.e. grep, more, java info)</li>
<li>ssh:* - SSH connections</li>
<li>system:* - OSGi framework management</li>
<li>web:* - WAR bundle management</li>
<li>wrapper:* - OS service installation</li>
</ul>
<h3 id="Karaf的Web控制台"><a href="#Karaf的Web控制台" class="headerlink" title="Karaf的Web控制台"></a>Karaf的Web控制台</h3><p>启动Karaf后，在命令行输入<code>feature install webconsole</code>， 然后访问：<a href="http://localhost:8080/system/console" target="_blank" rel="external">http://localhost:8080/system/console</a>  </p>
<p><img src="/images/java_osgi_karaf_webconsole.png" alt="Karaf WebConsole"></p>
<h3 id="Karaf远程管理"><a href="#Karaf远程管理" class="headerlink" title="Karaf远程管理"></a>Karaf远程管理</h3><p>Karaf启动时会启动一个SSHd Server，可以通过SSH远程访问Karaf。Karaf通过<code>KARAF_ETC/org.apache.karaf.shell.cfg</code>文件管理SSH服务相关的配置。详细<br>信息可参考<a href="http://karaf.apache.org/manual/latest/users-guide/remote.html" target="_blank" rel="external">Karaf文档</a></p>
<h3 id="Karaf-Logging日志服务"><a href="#Karaf-Logging日志服务" class="headerlink" title="Karaf Logging日志服务"></a>Karaf Logging日志服务</h3><p>Karaf 通过Pax Logging聚合了当前各个主流日志框架，通过<code>org.ops4j.pax.logging.cfg</code>可以对日志服务进行配置管理，通过命令行命令可以方便的<br>切换日志级别，查看日志输出。</p>
<p><img src="/images/java_osgi_karaf_logging.png" alt="Karaf WebConsole"></p>
<h3 id="Karaf配置服务"><a href="#Karaf配置服务" class="headerlink" title="Karaf配置服务"></a>Karaf配置服务</h3><p>Karaf的配置服务功能非常强大，用户可以为每个bundle进行独立配置。Karaf的bundle配置遵循OSGi <strong>Service Config Admin服务</strong>，<br>并通过<a href="http://felix.apache.org/documentation/subprojects/apache-felix-file-install.html" target="_blank" rel="external">Felix File Install</a>组件<br>实时监控KARAF_ETC目录，自动启用变更的配置。</p>
<p><img src="/images/java_osgi_karaf_config_1.png" alt="Karaf WebConsole"></p>
<h3 id="Karaf-Web-Application支持"><a href="#Karaf-Web-Application支持" class="headerlink" title="Karaf Web Application支持"></a>Karaf Web Application支持</h3><p>Karaf通过<a href="https://github.com/ops4j/org.ops4j.pax.web" target="_blank" rel="external">Pax Web</a>提供对Web应用的支持。通过标准的OSGi HTTP Service，可以将Web应用资源注册为OSGi服务。<br>此外，Pax Web支持直接部署War和Wab，并支持CDI。Pax Web 4.0.x特性如下：  </p>
<ul>
<li>Servlet 3.0</li>
<li>JSP 2.0</li>
<li>JSF 2.1</li>
<li>Jetty 9.0.x</li>
<li>Tomcat 7.x (still experimental, but better supported)</li>
<li>support of CDI (through Pax-CDI)</li>
<li>support of only Servlet 3.0 annotated Servlets in JAR</li>
<li>Web-Fragments</li>
</ul>
<p><img src="/images/java_osgi_karaf_webapp.png" alt="Karaf WebConsole"></p>
<h3 id="Karaf-Persistence服务"><a href="#Karaf-Persistence服务" class="headerlink" title="Karaf Persistence服务"></a>Karaf Persistence服务</h3><p>Karaf 通过<a href="http://aries.apache.org/modules/jpaproject.html" target="_blank" rel="external">Apache Aries JPA</a>为OSGi Bundle开发提供JPA支持。</p>
<p><img src="/images/java_osgi_karaf_jpa.png" alt="Karaf WebConsole"></p>
<h2 id="OSGi项目结构及Karaf的部署"><a href="#OSGi项目结构及Karaf的部署" class="headerlink" title="OSGi项目结构及Karaf的部署"></a>OSGi项目结构及Karaf的部署</h2><h3 id="OSGi项目结构"><a href="#OSGi项目结构" class="headerlink" title="OSGi项目结构"></a>OSGi项目结构</h3><p>通常，一个J2EE项目以OSGi模块化开发时，会根据项目的J2EE架构分层和业务模块进行粒度拆分。下面是一个典型的J2EE项目到OSGi项目的架构映射：</p>
<p><img src="/images/java_osgi_karaf_osgi_app.png" alt="Karaf WebConsole"><br>该项目来自：<a href="https://github.com/Cloudyle/petclinic" target="_blank" rel="external">https://github.com/Cloudyle/petclinic</a></p>
<h3 id="Karaf的项目部署"><a href="#Karaf的项目部署" class="headerlink" title="Karaf的项目部署"></a>Karaf的项目部署</h3><p>Karaf支持下列构件的部署：<br>Bundles<br>Blueprint files (xml)<br>Features<br>Kar Archives<br>“plain” jar files</p>
<p><img src="/images/java_osgi_karaf_deploy_1.png" alt="Karaf Deployment"></p>
<p>通常的部署模式基本可以支持产品项目的部署需求。根据项目的实际需要，也可以对Karaf进行裁剪以更适合产品的定制需求。<br>这种方式，可以将部署构件发布到<code>KARAF_HOME/system</code>下，将构件定义的Feature在<code>org.apache.karaf.features.cfg</code>中进行配置。</p>
<p><img src="/images/java_osgi_karaf_deploy_2.png" alt="Karaf Deployment"><br><img src="/images/java_osgi_karaf_deploy_3.png" alt="Karaf Deployment"></p>
<h3 id="greeter-osgi-example的部署"><a href="#greeter-osgi-example的部署" class="headerlink" title="greeter-osgi-example的部署"></a><a href="https://github.com/christtrc/greeter-osgi-example" target="_blank" rel="external">greeter-osgi-example</a>的部署</h3><ol>
<li>在<code>greeter-osgi-example</code>项目主目录下，通过控制台执行<code>mvn clean install</code></li>
<li><p>启动Karaf，在控制台通过下述命令安装 <strong>greeter-service</strong> Feature：  </p>
<blockquote>
<p>feature:repo-add mvn:org.example.greeter.feature/greeter-feature-service/1.0.0-SNAPSHOT/xml/features<br>feature:install scr greeter-service</p>
</blockquote>
</li>
<li><p>通过下述命令安装 <strong>greeter-client</strong> Feature：  </p>
<blockquote>
<p>feature:repo-add mvn:org.example.greeter.feature/greeter-feature-client/1.0.0-SNAPSHOT/xml/features<br>feature:install scr greeter-client</p>
</blockquote>
</li>
<li><p>通过下面的命令可以查看bundle是否正确安装，服务是否正确启动并测试：</p>
<blockquote>
<p>la  #查看bundle列表<br>service:list | grep -i greeter  #查找服务是否正确启动<br>greeter geeker  #测试服务</p>
</blockquote>
</li>
</ol>
<h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><ul>
<li>通过上述介绍我们可以看到Karaf为OSGi开发提供了丰富的功能支持。实际上，通过Feature机制，Karaf为Spring，为整个J2EE体系提供了开发支持。</li>
<li>此外，Karaf通过Cellar子项目提供了集群扩展能力，并且支持Cloud部署。</li>
<li>下一篇文章我们将介绍Karaf在集群中的部署及应用，后续文章将基于此项目展开IT自动化过程。</li>
</ul>

          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>


    <footer class="post-footer">
      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
  <link itemprop="mainEntityOfPage" href="http://chrisrc.me/2015/07/31/java-osgi-dynamic-app-with-karaf-maven/">

  <span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <meta itemprop="name" content="chrisrc">
    <meta itemprop="description" content="">
    <meta itemprop="image" content="/images/avatar.gif">
  </span>

  <span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
    <meta itemprop="name" content="山中，山外与俯瞰">
    <span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject">
      <img style="display:none;" itemprop="url image" alt="山中，山外与俯瞰" src="">
    </span>
  </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2015/07/31/java-osgi-dynamic-app-with-karaf-maven/" itemprop="url">
                  Apache Karaf构建动态模块化应用(3)--使用Maven自动打包部署Bundle
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2015-07-31T16:18:42+08:00">
                2015-07-31
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
              <span class="post-meta-divider">|</span>
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/OSGi/" itemprop="url" rel="index">
                    <span itemprop="name">OSGi</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <a href="/2015/07/31/java-osgi-dynamic-app-with-karaf-maven/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2015/07/31/java-osgi-dynamic-app-with-karaf-maven/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          

          
          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p>前述文章谈了使用Bndtools在Eclipse中快速进行OSGi Bundle开发调试。这在产品功能开发阶段是高效的，<br>在面对产品的后续测试、打包分发，特别是自动打包、测试及部署过程，现有的工程结构将不能满足要求。采用Maven对项目<br>生命周期进行管理变得非常重要。<br>当然，也可以采用Gradle进行项目管理，大家可以自己去尝试。</p>
<h2 id="通过Maven进行Bundle开发"><a href="#通过Maven进行Bundle开发" class="headerlink" title="通过Maven进行Bundle开发"></a>通过Maven进行Bundle开发</h2><p>###Maven Bundle Plugin<br>在Bndtools之前的很长一段时间里，进行OSGi Bundle开发最通用的方式就是使用<a href="http://felix.apache.org/documentation/subprojects/apache-felix-maven-bundle-plugin-bnd.html" target="_blank" rel="external">Maven Bundle Plugin</a>。<br>Maven Bundle Plugin的底层依赖bnd工具实现bundle的分析，同时结合插件的配置，来构建bundle。采用此插件时，POM的package类型要设置为<code>bundle</code>。</p>
<p>采用Maven Bundle Plugin的另一个好处时，原生的Maven支持，因此不再局限于Eclipse，也可以在Intellij IDEA，Netbeans等IDE工具中进行开发。</p>
<p>###Bnd Maven Plugin<br>Bndtools自 2.4.1版本开始，发布了<a href="https://github.com/bndtools/bnd/tree/master/bnd-maven-plugin" target="_blank" rel="external">bnd-maven-plugin</a>，通过与工程中的bnd相结合，可以提供工程的Maven支持。</p>
<p>考虑到Bndtools在开发调试OSGi bundle时的强大功能支持，建议使用此Maven插件替代上面的Maven Bundle Plugin。此插件的另一个优势在于，POM中的<br>package类型保持为<code>jar</code>即可。</p>
<h2 id="采用Bnd-Maven-Plugin管理Bundle开发"><a href="#采用Bnd-Maven-Plugin管理Bundle开发" class="headerlink" title="采用Bnd Maven Plugin管理Bundle开发"></a>采用Bnd Maven Plugin管理Bundle开发</h2><p>基于Maven Bundle Plugin的开发在网上有很多教程，这里不再详述。</p>
<p>Bndtools和Bnd Maven Plugin的强大功能来自于Bnd工具，因此熟悉Bnd的功能是非常必要的，Bnd的详细功能请参考<a href="http://bnd.bndtools.org/" target="_blank" rel="external">Bnd官方文档</a></p>
<h3 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h3><p>当前，由于Maven Jar Plugin的缺陷，位于target/classes/META-INF/MANIFEST.MF的文件会被maven-jar-plugin忽略，解决方案是在<br>maven-jar-plugin的POM配置中明确指明要打包的MANIFEST.MF文件：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">plugin</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-jar-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">archive</span>&gt;</span></div><div class="line">      <span class="tag">&lt;<span class="name">manifestFile</span>&gt;</span>$&#123;project.build.outputDirectory&#125;/META-INF/MANIFEST.MF<span class="tag">&lt;/<span class="name">manifestFile</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">archive</span>&gt;</span></div><div class="line">  <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></div></pre></td></tr></table></figure></p>
<p>maven-jar-plugin的配置可以放在工程的Parent POM中。</p>
<h3 id="项目结构"><a href="#项目结构" class="headerlink" title="项目结构"></a>项目结构</h3><p>前一篇文章使用Bndtools构建了greeter-api, greeter-service 和 greeter-client三个工程，因此，当前的工程结构是：</p>
<p>greeter-osgi-example  </p>
<pre><code>|----pom.xml      #Parent POM  
|----greeter-api  
          |----pom.xml  
          |----bnd.bnd  
          |---- ...  
|----greeter-service  
          |----pom.xml  
          |----bnd.bnd  
          |---- ...  
|----greeter-client  
          |----pom.xml  
          |----bnd.bnd  
          |---- ...  
</code></pre><p><strong>Parent POM</strong> 定义如下：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">"http://maven.apache.org/POM/4.0.0"</span> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></div><div class="line">         <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"</span>&gt;</div><div class="line">    <span class="tag">&lt;<span class="name">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="name">modelVersion</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.example.greeter<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>greeter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.0.0-SNAPSHOT<span class="tag">&lt;/<span class="name">version</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">packaging</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">packaging</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">modules</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">module</span>&gt;</span>greeter-api<span class="tag">&lt;/<span class="name">module</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">module</span>&gt;</span>greeter-service<span class="tag">&lt;/<span class="name">module</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">module</span>&gt;</span>greeter-client<span class="tag">&lt;/<span class="name">module</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">module</span>&gt;</span>greeter-feature-service<span class="tag">&lt;/<span class="name">module</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">module</span>&gt;</span>greeter-feature-client<span class="tag">&lt;/<span class="name">module</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">modules</span>&gt;</span></div><div class="line"></div><div class="line">    <span class="tag">&lt;<span class="name">build</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">pluginManagement</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-jar-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">useDefaultManifestFile</span>&gt;</span>true<span class="tag">&lt;/<span class="name">useDefaultManifestFile</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></div><div class="line">                <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></div><div class="line">            <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></div><div class="line">        <span class="tag">&lt;/<span class="name">pluginManagement</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">build</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">project</span>&gt;</span></div></pre></td></tr></table></figure></p>
<p><strong>greeter-api</strong> 的POM定义如下：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">"http://maven.apache.org/POM/4.0.0"</span> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></div><div class="line">         <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"</span>&gt;</div><div class="line">    <span class="tag">&lt;<span class="name">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="name">modelVersion</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">parent</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.example.greeter<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>greeter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.0.0-SNAPSHOT<span class="tag">&lt;/<span class="name">version</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">parent</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.example.greeter<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>greeter-api<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">packaging</span>&gt;</span>jar<span class="tag">&lt;/<span class="name">packaging</span>&gt;</span></div><div class="line"></div><div class="line">    <span class="tag">&lt;<span class="name">build</span>&gt;</span></div><div class="line">        <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>biz.aQute.bnd<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>bnd-maven-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.4.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></div><div class="line">                <span class="tag">&lt;<span class="name">executions</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;<span class="name">execution</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;<span class="name">goals</span>&gt;</span></div><div class="line">                            <span class="tag">&lt;<span class="name">goal</span>&gt;</span>bnd-process<span class="tag">&lt;/<span class="name">goal</span>&gt;</span></div><div class="line">                        <span class="tag">&lt;/<span class="name">goals</span>&gt;</span></div><div class="line">                    <span class="tag">&lt;/<span class="name">execution</span>&gt;</span></div><div class="line">                <span class="tag">&lt;/<span class="name">executions</span>&gt;</span></div><div class="line">            <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></div><div class="line">        <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></div><div class="line">    <span class="tag">&lt;/<span class="name">build</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">project</span>&gt;</span></div></pre></td></tr></table></figure></p>
<p><strong>greeter-service</strong> 和 <strong>greeter-client</strong> 的POM定义请参考工程代码<a href="https://github.com/christtrc/greeter-osgi-example" target="_blank" rel="external">greeter-osgi-example</a>。</p>
<h3 id="编译、打包、-发布"><a href="#编译、打包、-发布" class="headerlink" title="编译、打包、 发布"></a>编译、打包、 发布</h3><p>在Eclipse中，选择单个工程或者主POM，右键，run执行时选择Maven Build，在运行配置的Goals里输入<code>clean install</code>，然后运行  </p>
<p><img src="/images/java_osgi_maven_build.png" alt="Osgi Maven Build"></p>
<p><strong>提示：如果多个团队协作，其他团队对当前团队的工程产生依赖，可以执行maven的deploy动作，将工程构件发布到内部Nexus仓库，其他团队可以通过<br>下载Maven依赖进行开发。也可以在Bndtools的Bundle仓库添加内部的Nexus仓库进行Bundle依赖开发。</strong></p>
<h3 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h3><p>基于Maven的Bundle开发对使用Bndtools进行开发完全没有侵入性，因此两种开发模式可以完美并存，同时，基于Maven的项目管理也为自动化测试，打包部署等<br>提供了支撑。</p>
<h2 id="通过Apache-Karaf的Feature特性进行Bundle分组管理"><a href="#通过Apache-Karaf的Feature特性进行Bundle分组管理" class="headerlink" title="通过Apache Karaf的Feature特性进行Bundle分组管理"></a>通过Apache Karaf的Feature特性进行Bundle分组管理</h2><p>关于<a href="http://karaf.apache.org/" target="_blank" rel="external">Apache Karaf</a>的详细介绍将在下一篇文章中展开，这里先讨论Bundle的分组管理。</p>
<p>基于Bundle粒度化开发时，我们将获得很多的bundle，这些bundle如何进行管理内？一种方式时所有的bundle直接混合部署，这对几个，十几个bundle的情况<br>是可以接受的，当bundle的数量达到几十，上百甚至上千个时，混合部署将变得非常复杂而且容易出错。</p>
<p>Apache Karaf的Feature提供了一种通过Feature XML描述文件对bundle进行分组管理，最终形成一棵Bundle树,例如：<br><img src="/images/java_osgi_maven_karaf_feature.png" alt="Karaf Feature"></p>
<p>Greeter OSGi Example中，我们建立了两个Feature：  </p>
<ul>
<li>greeter-service  包括：<code>greeter-api</code> 和 <code>greeter-service</code> 两个bundle</li>
</ul>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">feature</span> <span class="attr">name</span>=<span class="string">"greeter-service"</span> <span class="attr">version</span>=<span class="string">"$&#123;project.version&#125;"</span> <span class="attr">install</span>=<span class="string">"auto"</span>&gt;</span></div><div class="line"></div><div class="line">  <span class="tag">&lt;<span class="name">feature</span>&gt;</span>cellar<span class="tag">&lt;/<span class="name">feature</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">feature</span>&gt;</span>cellar-dosgi<span class="tag">&lt;/<span class="name">feature</span>&gt;</span></div><div class="line"></div><div class="line">  <span class="tag">&lt;<span class="name">bundle</span>&gt;</span>mvn:org.example.greeter/greeter-api/1.0.0-SNAPSHOT<span class="tag">&lt;/<span class="name">bundle</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">bundle</span>&gt;</span>mvn:org.example.greeter/greeter-service/1.0.0-SNAPSHOT<span class="tag">&lt;/<span class="name">bundle</span>&gt;</span></div><div class="line"></div><div class="line"><span class="tag">&lt;/<span class="name">feature</span>&gt;</span></div></pre></td></tr></table></figure>
<ul>
<li>greeter-client  包括：<code>greeter-api</code> 和 <code>greeter-client</code> 两个bundle</li>
</ul>
<pre><code class="xml"><span class="tag">&lt;<span class="name">feature</span> <span class="attr">name</span>=<span class="string">"greeter-client"</span> <span class="attr">version</span>=<span class="string">"${project.version}"</span> <span class="attr">install</span>=<span class="string">"auto"</span>&gt;</span>

    <span class="tag">&lt;<span class="name">feature</span>&gt;</span>cellar<span class="tag">&lt;/<span class="name">feature</span>&gt;</span>
    <span class="tag">&lt;<span class="name">feature</span>&gt;</span>cellar-dosgi<span class="tag">&lt;/<span class="name">feature</span>&gt;</span>

    <span class="tag">&lt;<span class="name">bundle</span>&gt;</span>mvn:org.example.greeter/greeter-api/1.0.0-SNAPSHOT<span class="tag">&lt;/<span class="name">bundle</span>&gt;</span>
    <span class="tag">&lt;<span class="name">bundle</span>&gt;</span>mvn:org.example.greeter/greeter-client/1.0.0-SNAPSHOT<span class="tag">&lt;/<span class="name">bundle</span>&gt;</span>

  <span class="tag">&lt;/<span class="name">feature</span>&gt;</span>
</code></pre>
<p>关于这两个Feature的应用，将在后续文中逐步介绍。</p>
<h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><ul>
<li>通过本文，我们可以发现，随着Bndtools功能的不断完善，基于Maven管理OSGi Bundle变得非常简单。</li>
<li>采用Maven管理OSGi Bundle的优势我们将在后续文章中逐步展示。</li>
</ul>

          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>


    <footer class="post-footer">
      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
  <link itemprop="mainEntityOfPage" href="http://chrisrc.me/2015/07/29/java-osgi-dynamic-app-with-karaf-bndtools/">

  <span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <meta itemprop="name" content="chrisrc">
    <meta itemprop="description" content="">
    <meta itemprop="image" content="/images/avatar.gif">
  </span>

  <span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
    <meta itemprop="name" content="山中，山外与俯瞰">
    <span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject">
      <img style="display:none;" itemprop="url image" alt="山中，山外与俯瞰" src="">
    </span>
  </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2015/07/29/java-osgi-dynamic-app-with-karaf-bndtools/" itemprop="url">
                  Apache Karaf构建动态模块化应用(2)--使用Bndtools开发Bundle
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2015-07-29T20:38:35+08:00">
                2015-07-29
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
              <span class="post-meta-divider">|</span>
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/OSGi/" itemprop="url" rel="index">
                    <span itemprop="name">OSGi</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <a href="/2015/07/29/java-osgi-dynamic-app-with-karaf-bndtools/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2015/07/29/java-osgi-dynamic-app-with-karaf-bndtools/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          

          
          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="Bndtools"><a href="#Bndtools" class="headerlink" title="Bndtools"></a>Bndtools</h2><p><a href="http://bndtools.org/" target="_blank" rel="external">Bndtools</a>是Neil Bartlett基于OSGi推动者Peter Kriens开发的<a href="http://www.aqute.biz/Bnd/Bnd" target="_blank" rel="external">Bnd工具</a>创建的图形化开发工具。Bnd已成为OSGi开发<br>工具中的底层基础构件，Maven Bundle Plugin插件的实现也是基于Bnd。目前，通过Bnd/Bndtools已经可以为OSGi开发提供完整的生态支持。</p>
<h2 id="Bndtools的特性"><a href="#Bndtools的特性" class="headerlink" title="Bndtools的特性"></a>Bndtools的特性</h2><ul>
<li>导入分析<br>不同于使用依赖描述文件，Bndtools通过字节码分析精确计算OSGi Bundle的依赖。</li>
<li>Bundle仓库<br>Bndtools提供了一个可插件式的Bundle仓库，这个仓库既可用于开发过程也可以在运行时使用，并且可以和OBR及Maven/Nexus对接。</li>
<li>依赖解析<br>Bndtools使用OSGi Resolver规范解析运行时依赖，开发人员仅关注直接bundle依赖即可。</li>
<li>自动版本控制<br>Bndtools的 <strong>Release</strong> 功能可以将bundle发布到仓库，在发布时可以自动与之前的版本基线进行比较，确定bundle和package的版本。</li>
<li>即时编译<br>借助于Eclipse自动编译保存的代码的功能，Bndtools在此基础上自动打包bundle，因此，开发调试时，bundle始终包含了最新代码。</li>
<li>集成测试<br>Bndtools包含了一个OSGi运行时用于集成测试，可以为选定的一组bundle启动OSGi框架，并在测试结束时停止框架，测试结果集成显示在Eclipse JUnit视图上。</li>
</ul>
<h2 id="Bndtools的安装"><a href="#Bndtools的安装" class="headerlink" title="Bndtools的安装"></a>Bndtools的安装</h2><p>通过Eclipse: <strong>Help -&gt; Eclipse MarketPlace…</strong> 下载安装Bndtools插件：<br><img src="/images/java_osgi_bndtools_install.png" alt="Bndtools Install"></p>
<h2 id="Bndtools开发示例"><a href="#Bndtools开发示例" class="headerlink" title="Bndtools开发示例"></a>Bndtools开发示例</h2><p>下面的示例已经成为OSGi开发的经典示例，这里仍借用此例，重点在于验证Bndtools的易用性和OSGi开发中的一些重要概念。</p>
<p><img src="/images/java_osgi_bndtools_example.png" alt="Bndtools Demo"></p>
<p>此示例包括四个部分，既演示了Java中最重要的 <strong>接口分离开发策略</strong>，也演示了OSGi <strong>Bundle粒度控制</strong>，OSGi <strong>服务的发布与使用</strong>。</p>
<ul>
<li>API Bundle包含服务接口</li>
<li>Provider Bundle提供了服务接口的一个实现</li>
<li>Command Bundle使用接口服务，并注册为felix shell command服务实现</li>
<li>通过Felix Shell控制台调用命令服务</li>
</ul>
<h3 id="创建API-接口Bundle工程"><a href="#创建API-接口Bundle工程" class="headerlink" title="创建API 接口Bundle工程"></a>创建API 接口Bundle工程</h3><p>在前述Bndtools插件成功安装之后，进入Eclipse：<strong>File&gt; New&gt; Project</strong> 向导，选择 <strong>Bndtools OSGi Project</strong> :<br><img src="/images/java_osgi_bndtools_proj1.png" alt="Bnd API Bundle"></p>
<p>在“New Bndtools OSGi Project”界面，设定工程命名为“greeter-api”:<br><img src="/images/java_osgi_bndtools_proj2.png" alt="Bnd API Bundle"></p>
<p>在下一步的Project Template中，为API Bundle选择 <strong>Empty Project</strong> 模板:<br><img src="/images/java_osgi_bndtools_proj3.png" alt="Bnd API Bundle"></p>
<p>其他保持默认，完成项目创建。</p>
<p>在第一次创建Bndtools OSGi Project时，点击完成项目创建后会弹出界面，提示创建Bndtools Configuration环境（Bndtools使用一个名为 <strong>cnf</strong> 的<br>项目保存本地Bundle仓库和共享的Bundle配置），如下图所示：</p>
<p><img src="/images/java_osgi_bndtools_proj4.png" alt="Bnd API Bundle">  </p>
<p>选择创建配置项目，按下一步，设定配置项目的模板（Bndtools支持Bundle-Hub， JPM4J和OSGi enRoute三种配置，enRoute仍在验证阶段，不太稳定，默认选择Bundle-Hub即可。）：</p>
<p><img src="/images/java_osgi_bndtools_proj5.png" alt="Bnd API Bundle">  </p>
<p><strong>注意：第一次创建cnf配置项目时，可能会因为网络问题持续很长时间，耐心等待即可</strong></p>
<p>上述步骤成功后，显示如下工程界面：<br><img src="/images/java_osgi_bndtools_proj6.png" alt="Bnd API Bundle">  </p>
<p>Bndtools OSGi项目中，最重要的文件即为.bnd文件，默认为bnd.bnd, <strong>Content</strong> 页签显示和编辑Bundle的描述信息， <strong>Build</strong> 页签控制Bundle编译依赖，<br><strong>Run</strong> 页签可以运行和调试Bundle。</p>
<p>工程界面的左下方为Bundle仓库列表，包括：  </p>
<ul>
<li>Workspace项目Bundle仓库</li>
<li>Build Bundle仓库</li>
<li>Release Bundle仓库</li>
<li>Local Bundle仓库</li>
<li>Bundle-Hub Bundle仓库</li>
</ul>
<p>如果想添加第三方Bundle仓库，如<a href="http://repository.amdatu.org/" target="_blank" rel="external">Amdatu</a>等，可以编辑 <strong>cnf&gt; ext&gt; repositories.bnd</strong> 文件，添加新的仓库。</p>
<p><img src="/images/java_osgi_bndtools_repo.png" alt="Bndtools Repo">  </p>
<p><br><br><strong>添加Greeter服务接口</strong></p>
<p>添加包：<code>org.example.greeter.api</code>，并按下面的代码定义接口：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">package</span> org.example.greeter.api;</div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Greeter</span> </span>&#123;</div><div class="line">	<span class="function">String <span class="title">sayHello</span><span class="params">(String name)</span></span>;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>在前面提到的bnd.bnd的Content页签，将包<code>org.example.greeter.api</code>添加到 <strong>Export Packages</strong> 列表。</p>
<p>API Bundle构建完成。</p>
<h3 id="创建服务提供者Bundle工程"><a href="#创建服务提供者Bundle工程" class="headerlink" title="创建服务提供者Bundle工程"></a>创建服务提供者Bundle工程</h3><ul>
<li><p>工程名定义为<code>greeter-service</code>, 在Project Template向导页面，选择 ‘Component Development’ ，其他默认。<br><img src="/images/java_osgi_bndtools_proj7.png" alt="Bnd API Bundle"></p>
</li>
<li><p>在bnd的Build页签添加“greeter-api” bundle依赖</p>
</li>
<li><p>添加包：<code>org.example.greeter.service</code>，并添加GreeterService.java:</p>
</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">import org.example.greeter.api.Greeter;</div><div class="line">import aQute.bnd.annotation.component.Component;</div><div class="line"></div><div class="line">@Component(properties=&#123;&quot;service.exported.interfaces=*&quot;&#125;)</div><div class="line">public class GreeterService implements Greeter &#123;</div><div class="line"></div><div class="line">	@Override</div><div class="line">	public String sayHello(String name) &#123;</div><div class="line">		return &quot;Hello &quot; + name + &quot;!, This is a demo!!&quot;;</div><div class="line">	&#125;</div><div class="line"></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<ul>
<li>在bnd的Content页签，将<code>org.example.greeter.service</code>加入到Private Packages列表</li>
</ul>
<p>到此， 服务实现bundle构建完成。</p>
<p><strong>服务实现Bundle的运行与调试</strong></p>
<ul>
<li>右键选择greeter-service工程，<strong>New&gt; Run Descriptor</strong> 添加launch.bnd运行配置，如下图所示：</li>
</ul>
<p><img src="/images/java_osgi_bndtools_run.png" alt="Bndtools Run"></p>
<ul>
<li>左侧，选择运行的OSGi框架，如果框架列表里没有选项，可先到Bundle-Hub仓库中下载<code>org.apapche.felix.framework</code> 或者 <code>org.eclipse.equinox</code>  </li>
<li>在右侧,选择 <strong>Run Requirements</strong> 列表中添加要运行的bundle，点击下方的“Resolve”，成功解析后，要运行的bundle及运行时依赖会自动添加到下方<br>的“Run Bundle” 列表。</li>
<li>点击上方的“Run OSGi” 或 “Debug OSGi”按钮，运行或调试bundle，调试时直接在bundle代码里添加断点即可。</li>
<li>运行结果如下图所示：</li>
</ul>
<p><img src="/images/java_osgi_bndtools_run_result.png" alt="Bndtools Run Result"></p>
<h3 id="调用服务实现的Client-Bundle"><a href="#调用服务实现的Client-Bundle" class="headerlink" title="调用服务实现的Client Bundle"></a>调用服务实现的Client Bundle</h3><p>限于篇幅，调用服务提供者的Client Bundle不再详述，具体可参考工程代码<a href="https://github.com/christtrc/greeter-osgi-example" target="_blank" rel="external">greeter-osgi-example</a>。</p>
<h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><ul>
<li>Bndtools及SCR等工具和框架为快速开发OSGi应用提供了良好的支持，使得基于OSGi的开发不再因为复杂而饱受诟病。</li>
<li>在下一篇文章中，我们将在现有代码的基础上更进一步，采用 <strong>Maven</strong> 管理OSGi工程，以实现后续的Karaf部署及 <strong>IT自动化</strong>。</li>
</ul>

          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>


    <footer class="post-footer">
      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
  <link itemprop="mainEntityOfPage" href="http://chrisrc.me/2015/07/27/java-osgi-build-dynamic-app-with-karaf/">

  <span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <meta itemprop="name" content="chrisrc">
    <meta itemprop="description" content="">
    <meta itemprop="image" content="/images/avatar.gif">
  </span>

  <span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
    <meta itemprop="name" content="山中，山外与俯瞰">
    <span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject">
      <img style="display:none;" itemprop="url image" alt="山中，山外与俯瞰" src="">
    </span>
  </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2015/07/27/java-osgi-build-dynamic-app-with-karaf/" itemprop="url">
                  Apache Karaf构建动态模块化应用(1)--OSGi回顾
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2015-07-27T09:41:27+08:00">
                2015-07-27
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
              <span class="post-meta-divider">|</span>
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/OSGi/" itemprop="url" rel="index">
                    <span itemprop="name">OSGi</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <a href="/2015/07/27/java-osgi-build-dynamic-app-with-karaf/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2015/07/27/java-osgi-build-dynamic-app-with-karaf/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          

          
          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="OSGi的体会"><a href="#OSGi的体会" class="headerlink" title="OSGi的体会"></a>OSGi的体会</h2><p>我所接触到的第一个OSGi项目是Oscar，迁移到Apache基金会后，就成了现在的Apache Felix。当初的需求是为JVM中并行运行的业务链提供隔离的资源配置。<br>看到Oscar，知道了OSGi框架规范，阅读了其代码实现，裁剪修改后用到了当时的产品之中，效果很好，于是，OSGi也就成了我持续关注的技术。</p>
<p>OSGi在WEB应用方面的发展，经过了这么多年，还是相对小众，主要是现有JVM ClassLoader功能的固化，J2EE体系的成熟稳定，单个Web应用系统的规模相对可控，OSGi对J2EE的工具支持相对落后，<br>众多因素导致OSGi的应用局限在J2SE级别，特别是Eclipse社区。</p>
<p>虽然OSGi的发展及应用未在企业应用端大规模普及，但OSGi在Java技术中的<strong>Jar包(bundle)层面</strong>的模块化隔离及基于接口服务的解耦机制为模块化应用开发<br>提供了一种很好的思路。当前最火爆的<strong>Docker</strong>技术，也是应用模块化及隔离技术在系统层面的一种新思路。</p>
<h2 id="OSGi的最新进展"><a href="#OSGi的最新进展" class="headerlink" title="OSGi的最新进展"></a>OSGi的最新进展</h2><ul>
<li>在关于JDK提供模块化功能中OSGi方案（JSR277/JSR291）被JCP社区（主要是Oracle）放弃后，JDK模块化系统支持方案将在<br>即将发布的下一个版本JDK9中提供（jigsaw in jdk9）。</li>
<li>OSGi技术规范及应用仍在向前推进，目前已经发布了<a href="http://www.osgi.org/Download/Release6" target="_blank" rel="external">R6版本</a>，OSGi联盟关注的重心开始<br>转向物联网IOT领域相关规范的制定与应用，希望有所突破。<br><img src="/images/java_osgi_bigpuzzle.png" alt="OSGi for IOT"></li>
<li>当前实现OSGi规范的框架主要有：<ul>
<li><a href="http://www.eclipse.org/equinox/" target="_blank" rel="external">Equinox</a> (R6)</li>
<li><a href="http://felix.apache.org/" target="_blank" rel="external">Apache Felix</a> (Oscar)  (R6)</li>
<li><a href="http://knopflerfish.org/" target="_blank" rel="external">Knopflerfish OSGi</a>  (R5)</li>
<li>Concierge (R5)</li>
<li>JBoss (R4.2)</li>
<li>ProSyst</li>
</ul>
</li>
<li>当前，OSGi规范的主推者Peter Kriens（bnd/bndtools工具的贡献者）正在致力于一个叫做<strong>OSGi enRoute</strong>的新应用框架，在这个框架中，他提出了一个<br>叫做μservice模型的概念（与最近火爆的<code>微服务</code>相对应），希望能够快速适应互联网现代应用和物联网应用的开发。关于enRoute框架可参考他的<br>文章<a href="https://jaxenter.com/osgi-enroute-a-new-framework-for-osgi-applications-117514.html" target="_blank" rel="external">OSGi enRoute – a new framework for OSGi applications</a></li>
</ul>
<h2 id="OSGi概述"><a href="#OSGi概述" class="headerlink" title="OSGi概述"></a>OSGi概述</h2><h3 id="OSGi框架"><a href="#OSGi框架" class="headerlink" title="OSGi框架"></a>OSGi框架</h3><p>从网络上搜索OSGi，大家可以看到很多介绍性的文章，了解OSGi的最好途径除了这些文章之外，下载OSGi的Release规范进行阅读是最直接的一个途径。<br>OSGi框架的结构还是要贴一下：<br><img src="/images/java_osgi_framework.png" alt="OSGi Framework"></p>
<h3 id="OSGi-Bundle"><a href="#OSGi-Bundle" class="headerlink" title="OSGi Bundle"></a>OSGi Bundle</h3><p>简单来说，OSGi框架通过JAVA ClassLoader机制在JVM内为每一个jar包提供了一个隔离的环境。这些隔离的环境想要交互必须通过Jar包内定义的MANIFEST.MF文件<br>声明环境对其他环境的依赖，环境对外暴露的资源等。OSGi用Bundle的概念封装jar，即在MANIFEST.MF中定义了OSGi标准描述符的jar。<br><img src="/images/java_osgi_bundle.png" alt="OSGi Bundle"></p>
<p>当前，大多数第三方Java项目都已经将发布包打包成了OSGi Bundle，以slf4j api包为例，我们来看一下Bundle的描述符：  </p>
<blockquote>
<p><strong>Manifest-Version:</strong> 1.0<br><strong>Archiver-Version</strong>: Plexus Archiver<br><strong>Created-By</strong>: Apache Maven<br><strong>Build-Jdk</strong>: 1.7.0_17<br><strong>Built-By</strong>: ceki<br><strong>Bundle-Description</strong>: The slf4j API<br><strong>Bundle-Version</strong>: 1.7.12<br><strong>Implementation-Version</strong>: 1.7.12<br><strong>Implementation-Title</strong>: slf4j-api<br><strong>Bundle-ManifestVersion</strong>: 2<br><strong>Bundle-SymbolicName</strong>: slf4j.api<br><strong>Bundle-Name</strong>: slf4j-api<br><strong>Bundle-Vendor</strong>: SLF4J.ORG<br><strong>Bundle-RequiredExecutionEnvironment</strong>: J2SE-1.5<br><strong>Export-Package</strong>: org.slf4j;version=1.7.12,   org.slf4j.spi;version=1.7.12<br>, org.slf4j.helpers;version=1.7.12<br><strong>Import-Package</strong>: org.slf4j.impl;version=1.6.0</p>
</blockquote>
<p><code>Bundle-SymbolicName</code> 和 <code>Bundle-Version</code> 唯一标识这个jar包; <code>Export-Package</code> 向外部环境公开资源，即那些package可以被访问;<br><code>Import-Package</code>说明这个Bundle要正常使用需要哪些外部环境就绪。</p>
<h3 id="OSGi类加载"><a href="#OSGi类加载" class="headerlink" title="OSGi类加载"></a>OSGi类加载</h3><p>JAVA中Package及类的隔离需要通过类加载器ClassLoader实现，通常的Java应用中一个类加载器加载所有应用及依赖类包，如下图所示：<br><img src="/images/java_osgi_classloader_1.png" alt="传统类加载"></p>
<p>在OSGi中，框架为每个bundle构建一个独立的类加载器，来限定jar包的访问边界。这些类加载器共享OSGi框架（System Bundle）的类加载器：<br><img src="/images/java_osgi_classloader_2.png" alt="OSGi类加载"></p>
<p>在这种模式下，每一个Bundle都有了一个自己的类域，每个Bundle只能看到框架公布的类资源，内部的类资源以及通过Import-Package声明引入<br>的其他类资源。<br><img src="/images/java_osgi_classloader_3.png" alt="OSGi Bundle类域"></p>
<h3 id="OSGi-Bundle开发基础"><a href="#OSGi-Bundle开发基础" class="headerlink" title="OSGi Bundle开发基础"></a>OSGi Bundle开发基础</h3><p>在OSGi中每一个Bundle都是隔离可控的，因此，OSGi框架可以很容易的控制Bundle的生命周期：<br><img src="/images/java_osgi_bundle_lifecycle.png" alt="Bundle生命周期"></p>
<p>通过Bundle生命周期控制，我们可以很容易的实现Bundle的动态加载和卸载，实现热替换。</p>
<p>OSGi框架为Bundle开发提供了标准的接口，如BundleActivator接口可以控制Bundle的启动和停止，*Listener接口可以监听框架、Bundle及服务<br>事件并做出响应等：</p>
<ul>
<li>Bundle Activator</li>
<li>提供一个服务</li>
<li>调用一个服务</li>
<li>使用FrameworkListener 监听框架事件</li>
<li>使用BundleListener监听Bundle生命周期事件</li>
<li>使用ServiceListener 监听服务的变化</li>
<li>使用ServiceFactory 动态创建服务</li>
<li>使用ServiceTracker 跟踪服务</li>
<li>使用filters过滤服务</li>
</ul>
<p>在进行OSGi开发时，必须熟悉上述基础开发，才能理解OSGi的动态特性。但是，所有的功能都从这些基础做起，系统的开发将变得非常繁琐和复杂，<br>这也是由于OSGi的动态特性所导致的，因为在OSGi中，Bundle、Service、Config等一切都是动态的，以Service为例：</p>
<ul>
<li>服务可能还没就绪</li>
<li>服务可能已经停止了</li>
<li>服务可能存在多个</li>
<li>服务可能失败</li>
</ul>
<p>为每个服务考虑上述动态特性，代码将变得非常复杂。此时，需要借助一个编程实践和框架来简化开发，让开发人员享受动态优势的同时，又能<br>专注于思考业务实现，如：</p>
<ul>
<li>Felix Dependency Manager</li>
<li>Service Component Runtime (SCR)</li>
<li>Apache Aries Blueprint</li>
</ul>
<p><strong>Service Component Runtime （SCR）</strong>  </p>
<p>最新的SCR服务已经支持通过注解的方式生命服务和引用，这极大的简化了在动态Bundle中对动态Service的维护。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Speak</span> </span>&#123; <span class="function"><span class="keyword">void</span> <span class="title">say</span><span class="params">(String text)</span></span>; &#125;</div><div class="line"></div><div class="line"><span class="meta">@Component</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SpeakLogImpl</span> <span class="keyword">implements</span> <span class="title">Speak</span> </span>&#123;</div><div class="line"></div><div class="line">    Logger logger;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">say</span><span class="params">(String text)</span> </span>&#123;</div><div class="line"></div><div class="line">      logger.info(text);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="meta">@Reference</span></div><div class="line">    <span class="function"><span class="keyword">void</span> <span class="title">setLog</span><span class="params">( Logger log)</span> </span>&#123; <span class="keyword">this</span>.logger = log; &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>对于如何使用SCR注解，请参考<a href="http://felix.apache.org/documentation/subprojects/apache-felix-maven-scr-plugin/scr-annotations.html" target="_blank" rel="external">SCR Annotations</a></p>
<p><strong>Apache Aries Blueprint （Blueprint）</strong>  </p>
<p>OSGi Blueprint规范是在Spring的基础上发展来的，它将Spring对Bean的管理移植到了OSGi环境下。<br><img src="/images/java_osgi_blueprint.png" alt="OSGi Blueprint"></p>
<p>在一个Bundle中，Blueprint的xml配置位于<strong>OSGI-INF/blueprnt/</strong> 目录下，xml的文件名可以根据需要定义。</p>
<p>下面是一个服务引用者Bundle的Blueprint配置文件示例：<br><img src="/images/java_osgi_blueprint_service_consumer.png" alt="Blueprint Service Consumer"><br>下面是一个服务发布者Bundle的Blueprint配置文件示例：<br><img src="/images/java_osgi_blueprint_service_provider.png" alt="Blueprint Service Consumer"></p>
<h2 id="OSGi-Bundle开发工具"><a href="#OSGi-Bundle开发工具" class="headerlink" title="OSGi Bundle开发工具"></a>OSGi Bundle开发工具</h2><p>当前，主流IDE环境都对OSGi开发提供了支持：  </p>
<ul>
<li>Eclipse Plugin Development</li>
<li>BndTools Plugin</li>
<li>Maven Bundle Plugin</li>
<li>BndTools Maven Plugin (New)</li>
<li>Netbeans Maven OSGi</li>
<li>Jetbrains IDEA Osmorc</li>
</ul>
<p>在这些开发工具中，<strong>BndTools</strong> 和 <strong>Maven Bundle Plugin</strong> 最为方便。 BndTools Maven Plugin是Maven Bundle Plugin的替代者。</p>
<h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><ul>
<li>当前随着移动互联网，物联网的快速发展，大数据，分布式和运计算等新的技术在不断出现，心的技术不再局限于单一语言平台，往往需要众多异构<br>系统紧密协作。OSGi如何适应这些新兴需求，我们将持续关注,感兴趣的可以查看<a href="https://github.com/osgi/design" target="_blank" rel="external">OSGi RFP/RFC文档</a>。</li>
<li>在OSGi系列的下一篇文章，我们将通过BndTools工具讲述如何快速简单的进行OSGi Bundle开发。</li>
</ul>

          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>


    <footer class="post-footer">
      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
  <link itemprop="mainEntityOfPage" href="http://chrisrc.me/2015/06/07/java-jni-with_swig/">

  <span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <meta itemprop="name" content="chrisrc">
    <meta itemprop="description" content="">
    <meta itemprop="image" content="/images/avatar.gif">
  </span>

  <span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
    <meta itemprop="name" content="山中，山外与俯瞰">
    <span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject">
      <img style="display:none;" itemprop="url image" alt="山中，山外与俯瞰" src="">
    </span>
  </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2015/06/07/java-jni-with_swig/" itemprop="url">
                  使用Swig封装DLL实现JNI快速开发
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2015-06-07T20:16:24+08:00">
                2015-06-07
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
              <span class="post-meta-divider">|</span>
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Snippets/" itemprop="url" rel="index">
                    <span itemprop="name">Snippets</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <a href="/2015/06/07/java-jni-with_swig/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2015/06/07/java-jni-with_swig/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          

          
          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="说在前面"><a href="#说在前面" class="headerlink" title="说在前面"></a>说在前面</h2><p>JNI这个话题原来比较老旧，是10年左右的事情，这次翻出来整理是因为又碰到了需求。现在网上介绍Swig的已经比较多了，有实际例子的比较少，<br>这里梳理的同时，做一个实际的例子。</p>
<p>JNI技术是在Java最初版本进行开发时就有了，主要实现Java语言与其他语言如C/C++/Delphi等的交互。<br>最初用到它是开发物联网的项目，产品需要与各种物联网终端进行适配对接，物联网终端的各个生产厂家提供的接口五花八门，<br>C，C++，Delphi的，接口封装的形式也是各不相同，为每一种设备做适配封装成为一个巨大的挑战。</p>
<p>在使用JNI封装了一个设备之后，脑力消耗巨大，因为用JNI封装一个简单的函数和封装几十上百个函数不是同一个等级的。为了快速解决问题，<br>只能在网上一遍遍搜索，最后发现了<a href="http://www.swig.org/" target="_blank" rel="external">Swig</a></p>
<h2 id="Swig简介"><a href="#Swig简介" class="headerlink" title="Swig简介"></a>Swig简介</h2><p>Swig的目标是为C/C++开发的程序与其他语言开发的程序之间建立连接。Swig支持的语言包括：Javascript, Perl, PHP, Python, Tcl and Ruby，<br>C#, Common Lisp (CLISP, Allegro CL, CFFI, UFFI), D, Go language, Java including Android, Lua, Modula-3, OCAML, Octave, Scilab and R。可以看出，几乎涵盖了大多数常用语言。</p>
<p>Swig的实现机制是通过定义中间接口描述文件，根据接口描述文件自动生成DLL的封装代码，包括C/C++封装代码和目标语言的封装代码。当前，<br>Swig支持C++的如下特性：  </p>
<ul>
<li>类</li>
<li>类的构造和析构</li>
<li>虚函数</li>
<li>公共继承（包括多重继承）</li>
<li>静态函数</li>
<li>函数和方法重载</li>
<li>大多数标准运算符的重载</li>
<li>引用</li>
<li>模板</li>
<li>函数指针</li>
<li>名字空间</li>
</ul>
<h2 id="Swig的安装"><a href="#Swig的安装" class="headerlink" title="Swig的安装"></a>Swig的安装</h2><p>Swig支持Windows，Linux和Mac。在Windows平台下，下载SwigWin-[VERSION]安装包即可；在Linux平台可以从仓库直接安装，如果想使用最新版本，<br>可以下载代码编译：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">./configure</div><div class="line">make</div><div class="line">make install</div></pre></td></tr></table></figure>
<p>最后的<code>make install</code>需要 <strong>root</strong> 权限。</p>
<h2 id="Swig在JNI中的应用"><a href="#Swig在JNI中的应用" class="headerlink" title="Swig在JNI中的应用"></a>Swig在JNI中的应用</h2><p>下面以一个实际的JNI封装案例简要介绍Swig的使用。</p>
<h3 id="待封装的DLL及头文件"><a href="#待封装的DLL及头文件" class="headerlink" title="待封装的DLL及头文件"></a>待封装的DLL及头文件</h3><p>通常拿到的SDK开发接口包括：DLL，.h头文件，.lib文件。下面的示例SDK接口包含：</p>
<ul>
<li>RR3036.dll</li>
<li>RR3036.h</li>
<li>RR3036.lib</li>
</ul>
<p>其中，头文件 <strong>RR3036.h</strong> 的部分内容摘录（仅占三分之一）如下：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div></pre></td><td class="code"><pre><div class="line">#ifdef RR3036_EXPORTS</div><div class="line">#define RR3036_API __declspec(dllexport)</div><div class="line">#else</div><div class="line">#define RR3036_API __declspec(dllimport)</div><div class="line">#endif</div><div class="line"></div><div class="line">// 此类是从 RR3036.dll 导出的</div><div class="line">class RR3036_API CRR3036 &#123;</div><div class="line">public:</div><div class="line">	CRR3036(void);</div><div class="line">&#125;;</div><div class="line"></div><div class="line">extern RR3036_API int nRR3036;</div><div class="line"></div><div class="line">RR3036_API int fnRR3036(void);</div><div class="line"></div><div class="line">#ifdef __cplusplus</div><div class="line">extern &quot;C&quot; &#123;</div><div class="line">#endif</div><div class="line"></div><div class="line">RR3036_API int CloseSpecComPort(int FrmHandle);</div><div class="line">RR3036_API int CloseComPort();</div><div class="line">RR3036_API int GetReaderInformation(unsigned char* ComAdr,				//读写器地址</div><div class="line">									unsigned char* VersionInfo,			//软件版本</div><div class="line">									unsigned char* ReaderType,				//读写器型号</div><div class="line">									unsigned char* TrType,		//支持的协议</div><div class="line">									unsigned char* ScanTime,</div><div class="line">									int frmComPortindex);</div><div class="line">RR3036_API int OpenComPort(int port,unsigned char *ComAdr,int* frmcomportindex);</div><div class="line">RR3036_API int AutoOpenComPort(int *port,unsigned char *ComAdr,int *frmcomportindex);</div><div class="line">RR3036_API int Inventory(unsigned char *ComAdr,</div><div class="line">						 unsigned char *state,				//询查模式</div><div class="line">						 unsigned char *AFI,</div><div class="line">						 unsigned char *pOUcharUIDList,		//标签DSFID + UID</div><div class="line">						 unsigned char *pOUcharTagNum,</div><div class="line">						 int frmcomportindex);</div><div class="line">RR3036_API int WriteInventoryScanTime(unsigned char *ComAdr,</div><div class="line">									  unsigned char *ScanTime,</div><div class="line">									  int frmComPortindex);</div><div class="line">RR3036_API int StayQuiet(unsigned char *ComAdr,</div><div class="line">						 unsigned char *UID,//要静默标签的UID</div><div class="line">						 unsigned char *ErrorCode,</div><div class="line">						 int frmcomportindex);</div><div class="line">RR3036_API int Select(unsigned char *ComAdr,</div><div class="line">					  unsigned char *UID,</div><div class="line">					  unsigned char *ErrorCode,</div><div class="line">					  int frmcomportindex);</div><div class="line">RR3036_API int ResetToReady(unsigned char *ComAdr,</div><div class="line">							unsigned char *state,</div><div class="line">							unsigned char *UID,</div><div class="line">							unsigned char *ErrorCode,</div><div class="line">							int frmcomportindex);</div><div class="line">RR3036_API int ReadSingleBlock(unsigned char *ComAdr,</div><div class="line">							   unsigned char *state,					//读模式选择</div><div class="line">							   unsigned char *UID,</div><div class="line">							   unsigned char blockNumber,			//块号</div><div class="line">							   unsigned char *BlockSecStatus,	//安全状态字</div><div class="line">							   unsigned char *Data,			//块数据</div><div class="line">							   unsigned char *ErrorCode,</div><div class="line">							   int frmcomportindex);</div><div class="line">RR3036_API int WriteSingleBlock(unsigned char *ComAdr,</div><div class="line">								unsigned char *state,				//读模式选择</div><div class="line">								unsigned char *UID,</div><div class="line">								unsigned char blockNumber,		//块号</div><div class="line">								unsigned char *Data,		//要写入的数据</div><div class="line">								unsigned char *ErrorCode,</div><div class="line">								int frmcomportindex);</div><div class="line">RR3036_API int ReadMultipleBlock(unsigned char *ComAdr,</div><div class="line">								 unsigned char *state,				//读模式选择</div><div class="line">								 unsigned char *UID,</div><div class="line">								 unsigned char BlockNum,	//起始块号</div><div class="line">								 unsigned char BlockCount,		//块数量</div><div class="line">								 unsigned char *BlockSecStatus,//安全状态字</div><div class="line">								 unsigned char *Data,		//块数据</div><div class="line">								 unsigned char *ErrorCode,</div><div class="line">								 int frmcomportindex);</div><div class="line">......</div></pre></td></tr></table></figure>
<h3 id="接口描述文件"><a href="#接口描述文件" class="headerlink" title="接口描述文件"></a>接口描述文件</h3><p>我们需要告诉Swig，我们的接口定义头文件是什么，要封装的主类（以Java为例）是什么，接口头文件是否还依赖其他头文件，<br>需要在交互过程中对哪些类型做什么样的映射封装，根据上述信息生成 <code>RR3036.i</code> 的接口描述文件，具体如下：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line">%module RR3036</div><div class="line">%&#123;</div><div class="line">%include &lt;windows.i&gt;</div><div class="line">%include &quot;RR3036.h&quot;</div><div class="line">%&#125;</div><div class="line"></div><div class="line">%include &lt;windows.i&gt;</div><div class="line">%include &quot;RR3036.h&quot;</div><div class="line"></div><div class="line">%include cpointer.i</div><div class="line">%pointer_functions(int, intp);</div><div class="line">%pointer_functions(unsigned char, shortp);</div><div class="line"></div><div class="line">%include &quot;carrays.i&quot;</div><div class="line">%array_functions(unsigned char, shortArray);</div></pre></td></tr></table></figure>
<p>如上所示，我们要封装成的Java代码主类为 <strong>RR3036</strong>（通过<code>%module</code>描述）。定义int型/短整型指针的类型映射封装。</p>
<p>由上面可以看出，这个过程我们几乎不需要考虑接口头文件中的具体接口方法定义。关于接口描述文件定义及类型封装请<br>参考<a href="http://www.swig.org/Doc3.0/SWIGDocumentation.html" target="_blank" rel="external">Swig帮助文档</a>。</p>
<h3 id="编译生成代码"><a href="#编译生成代码" class="headerlink" title="编译生成代码"></a>编译生成代码</h3><p>接口描述文件<code>RR3036.i</code>准备好之后就可以调用Swig命令生成封装代码，具体命令如下：</p>
<p><code>swig -c++ -java -package rr3036.api -outdir src/java/rr3036/api RR3036.i</code></p>
<p>生成的代码文件（本例）主要包括：</p>
<ul>
<li><p>两个C++封装文件：</p>
<ul>
<li>JNI_RR3036API.cpp</li>
<li>RR3036_wrap.cxx   注意，此文件中的<code>%include &lt;windows.i&gt; %include &quot;RR3036.i&quot;</code>需要调整才能编译</li>
</ul>
</li>
<li><p>多个Java封装文件：</p>
<ul>
<li>CRR3036.java</li>
<li>RR3036.java  # 要调用的主类</li>
<li>RR3036JNI.java</li>
<li>SWIGTYPE_p_int.java</li>
<li>SWIGTYPE_p_unsigned_char.java</li>
</ul>
</li>
</ul>
<p>对上述代码分别进行编译。</p>
<p><strong>备注：</strong></p>
<ul>
<li>生成的C++封装代码在Linux下的编译，在Swig中有单独说明，可参考。</li>
<li>详细编译参数，请参考Swig帮助文档。</li>
</ul>
<h3 id="调用代码"><a href="#调用代码" class="headerlink" title="调用代码"></a>调用代码</h3><p>将生成的<code>JNI_RR3036API.dll</code> 与 接口<code>RR3036.DLL</code> 通过<code>System.load</code>等方法加载后调用即可。</p>
<p>本例代码可从<a href="https://github.com/christtrc/swig-jni-rr3036" target="_blank" rel="external">swig-jni-rr3036</a>下载。</p>
<h2 id="附录"><a href="#附录" class="headerlink" title="附录"></a>附录</h2><p><a href="http://blog.csdn.net/pfgmylove/article/details/7052839" target="_blank" rel="external">[Android] Jni中C++和Java的数据类型的对应关系</a></p>
<table>
<thead>
<tr>
<th style="text-align:left">Java类型</th>
<th style="text-align:left">本地类型</th>
<th style="text-align:left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"></td>
</tr>
</tbody>
</table>
<p>boolean    |jboolean    |C/C++8位整型<br>byte    |jbyte    |C/C++带符号的8位整型<br>char    |jchar    |C/C++无符号的16位整型<br>short    |jshort    |C/C++带符号的16位整型<br>int        |jint|    |C/C++带符号的32位整型<br>long    |jlong    |C/C++带符号的64位整型e<br>float    |jfloat    |C/C++32位浮点型<br>double    |jdouble    |C/C++64位浮点型<br>Object    |jobject    |任何Java对象，或者没有对应java类型的对象<br>Class    |jclass      |Class对象<br>String    |jstring    |字符串对象<br>Object[]    |jobjectArray    |任何对象的数组<br>boolean[]    |jbooleanArray    |布尔型数组<br>byte[]    |jbyteArray    |比特型数组<br>char[]    |jcharArray    |字符型数组<br>short[]    |jshortArray    |短整型数组<br>int[]    |jintArray    |整型数组<br>long[]    |jlongArray    |长整型数组<br>float[]    |jfloatArray    |浮点型数组<br>double[]    |jdoubleArray    |双浮点型数组  </p>

          
        
      
    </div>

    <div>
      
    </div>

    <div>
      
    </div>


    <footer class="post-footer">
      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
  </section>

  
  <nav class="pagination">
    <a class="extend prev" rel="prev" href="/page/5/"><i class="fa fa-angle-left"></i></a><a class="page-number" href="/">1</a><span class="space">&hellip;</span><a class="page-number" href="/page/5/">5</a><span class="page-number current">6</span><a class="page-number" href="/page/7/">7</a><a class="extend next" rel="next" href="/page/7/"><i class="fa fa-angle-right"></i></a>
  </nav>



          </div>
          


          

        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    <div class="sidebar-inner">

      

      

      <section class="site-overview sidebar-panel sidebar-panel-active">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
          <img class="site-author-image" itemprop="image"
               src="/images/avatar.gif"
               alt="chrisrc" />
          <p class="site-author-name" itemprop="name">chrisrc</p>
          <p class="site-description motion-element" itemprop="description"></p>
        </div>
        <nav class="site-state motion-element">
          <div class="site-state-item site-state-posts">
            <a href="/archives">
              <span class="site-state-item-count">69</span>
              <span class="site-state-item-name">日志</span>
            </a>
          </div>

          
            <div class="site-state-item site-state-categories">
              <a href="/categories">
                <span class="site-state-item-count">21</span>
                <span class="site-state-item-name">分类</span>
              </a>
            </div>
          

          
            <div class="site-state-item site-state-tags">
              <a href="/tags">
                <span class="site-state-item-count">162</span>
                <span class="site-state-item-name">标签</span>
              </a>
            </div>
          

        </nav>

        

        <div class="links-of-author motion-element">
          
            
              <span class="links-of-author-item">
                <a href="https://github.com/christtrc" target="_blank" title="GitHub">
                  
                    <i class="fa fa-fw fa-github"></i>
                  
                  GitHub
                </a>
              </span>
            
              <span class="links-of-author-item">
                <a href="https://twitter.com/chrisrc" target="_blank" title="Twitter">
                  
                    <i class="fa fa-fw fa-twitter"></i>
                  
                  Twitter
                </a>
              </span>
            
          
        </div>

        
        
          <div class="cc-license motion-element" itemprop="license">
            <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" class="cc-opacity" target="_blank">
              <img src="/images/cc-by-nc-sa.svg" alt="Creative Commons" />
            </a>
          </div>
        

        
        

        


      </section>

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright" >
  
  &copy;  2015 - 
  <span itemprop="copyrightYear">2017</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">
     
      <a href="mailto:chrisrc@qq.com">chrisrc</a> 
    
  </span>
  <span class="author"> &nbsp; QQ: 58122705 </span>
</div>


<div class="powered-by">
  由 <a class="theme-link" href="https://hexo.io">Hexo</a> 强力驱动
</div>

<div class="theme-info">
  主题 -
  <a class="theme-link" href="https://github.com/iissnan/hexo-theme-next">
    NexT.Mist
  </a>
</div>


        

        
      </div>
    </footer>

    <div class="back-to-top">
      <i class="fa fa-arrow-up"></i>
    </div>
  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  



  
  <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>

  
  <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>

  
  <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.0"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.0"></script>



  
  

  

  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.0"></script>



  

  
    
  

  <script type="text/javascript">
    var duoshuoQuery = {short_name:"chrisrc"};
    (function() {
      var ds = document.createElement('script');
      ds.type = 'text/javascript';ds.async = true;
      ds.id = 'duoshuo-script';
      ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
      ds.charset = 'UTF-8';
      (document.getElementsByTagName('head')[0]
      || document.getElementsByTagName('body')[0]).appendChild(ds);
    })();
  </script>

  
    
    
    <script src="/lib/ua-parser-js/dist/ua-parser.min.js?v=0.7.9"></script>
    <script src="/js/src/hook-duoshuo.js"></script>
  








  
  

  

  

  
<script>
(function(){
    var bp = document.createElement('script');
    var curProtocol = window.location.protocol.split(':')[0];
    if (curProtocol === 'https') {
        bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';        
    }
    else {
        bp.src = 'http://push.zhanzhang.baidu.com/push.js';
    }
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(bp, s);
})();
</script>


  
<script>
(function(){
   var src = (document.location.protocol == "http:") ? "http://js.passport.qihucdn.com/11.0.1.js?ed903ab05fbc5fa64d95e4bfbf3d3a04":"https://jspassport.ssl.qhimg.com/11.0.1.js?ed903ab05fbc5fa64d95e4bfbf3d3a04";
   document.write('<script src="' + src + '" id="sozz"><\/script>');
})();
</script>

  


</body>
</html>
